xaizek / rocketgit (License: AGPLv3+) (since 2018-12-09)
Light and fast Git hosting solution suitable to serve both as a hub or as a personal code storage with its tickets, pull requests, API and much more.
Commit 561943c9bfd37fcf2b3c53724af2c8145d76d664

First round of notifications
Author: Catalin(ux) M. BOIE
Author date (UTC): 2012-11-18 12:03
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2012-11-18 12:03
Parent(s): 888934152ff5c2f2dafae9e598cf93ab6f377dba
Signing key:
Tree: 2e6dfed86c6c99b9a2f45eaab126415073eafb0b
File Lines added Lines deleted
.exclude 0 2
.gitignore 1 0
Makefile.in 12 8
README 2 0
TODO 29 0
duilder.conf 1 1
inc/bug.inc.php 0 1
inc/events.inc.php 236 0
inc/git.inc.php 0 1
inc/keys.inc.php 99 8
inc/mr.inc.php 0 1
inc/repo.inc.php 183 4
inc/rights.inc.php 0 1
inc/sql.inc.php 3 5
inc/state.inc.php 2 1
inc/struct.inc.php 136 3
inc/token.inc.php 0 1
inc/user.inc.php 55 5
inc/user/repo-page.php 11 5
inc/util.inc.php 47 8
inc/ver.php.in 2 0
rocketgit.spec.in 16 15
root/index.php 1 1
root/themes/default/index.html 1 1
root/themes/default/mail/user/key/del.body.txt 11 0
root/themes/default/mail/user/key/del.head.txt 3 0
root/themes/default/mail/user/key/del.subj.txt 1 0
root/themes/default/mail/user/key/new.body.txt 11 0
root/themes/default/mail/user/key/new.head.txt 3 0
root/themes/default/mail/user/key/new.subj.txt 1 0
root/themes/default/mail/user/repo/new.body.txt 17 0
root/themes/default/mail/user/repo/new.head.txt 3 0
root/themes/default/mail/user/repo/new.subj.txt 1 0
root/themes/default/mail/user/welcome.body.txt 12 0
root/themes/default/mail/user/welcome.head.txt 3 0
root/themes/default/mail/user/welcome.subj.txt 1 0
root/themes/default/repo/history/header.html 0 6
root/themes/default/repo/history/line.html 1 1
root/themes/default/repo/main.html 1 0
samples/cron 1 0
scripts/cron.php 5 2
scripts/events.php 107 0
tests/Makefile 4 1
tests/email.php 23 0
tests/event.php 92 0
File .exclude changed (mode: 100644) (index 06a4014..6b34cf2)
1 cata
2 1 *.log *.log
3 2 Makefile Makefile
4 3 *.out *.out
5 inspire
File .gitignore changed (mode: 100644) (index bf1d908..5ca30a3)
... ... cata/
9 9 *.out *.out
10 10 Changelog-last Changelog-last
11 11 *.lock *.lock
12 *.strace
File Makefile.in changed (mode: 100644) (index 310b5f5..5d69a2d)
... ... install: all
16 16 @mkdir -p $(I_ETC)/xinetd.d @mkdir -p $(I_ETC)/xinetd.d
17 17 cp -vd --no-clobber samples/rg $(I_ETC)/xinetd.d/rocketgit cp -vd --no-clobber samples/rg $(I_ETC)/xinetd.d/rocketgit
18 18 @mkdir -p $(I_ETC)/cron.d @mkdir -p $(I_ETC)/cron.d
19 cp -vd --no-clobber samples/cron $(I_ETC)/cron.d/rocketgit
19 cp -vd samples/cron $(I_ETC)/cron.d/rocketgit
20 20 @mkdir -p $(I_ETC)/httpd/conf.d @mkdir -p $(I_ETC)/httpd/conf.d
21 21 cp -vd --no-clobber samples/rg.conf $(I_ETC)/httpd/conf.d/rocketgit.conf cp -vd --no-clobber samples/rg.conf $(I_ETC)/httpd/conf.d/rocketgit.conf
22 22 @mkdir -p $(I_ETC)/rocketgit @mkdir -p $(I_ETC)/rocketgit
 
... ... install: all
24 24 cp -vd samples/config.php $(I_ETC)/rocketgit/config.php.sample cp -vd samples/config.php $(I_ETC)/rocketgit/config.php.sample
25 25 @mkdir -p $(I_ETC)/logrotate.d @mkdir -p $(I_ETC)/logrotate.d
26 26 cp -vd --no-clobber samples/logrotate $(I_ETC)/logrotate.d/rocketgit cp -vd --no-clobber samples/logrotate $(I_ETC)/logrotate.d/rocketgit
27 @mkdir -p $(I_VAR_LOG)/$(PRJ)
28 @-chown rocketgit:rocketgit $(I_VAR_LOG)/$(PRJ)
27 @mkdir -p --mode=0700 $(I_VAR_LOG)/$(PRJ)
28 @chown rocketgit:rocketgit $(I_VAR_LOG)/$(PRJ)
29 29 @chmod 0700 $(I_VAR_LOG)/$(PRJ) @chmod 0700 $(I_VAR_LOG)/$(PRJ)
30 @mkdir -p $(I_VAR_LOG)/$(PRJ)-web
31 @-chown apache:apache $(I_VAR_LOG)/$(PRJ)-web
32 @chmod 0700 $(I_VAR_LOG)/$(PRJ)-web
33 @mkdir -p $(I_VAR_LIB)/$(PRJ) $(I_VAR_LIB)/$(PRJ)/locks $(I_VAR_LIB)/$(PRJ)/repos $(I_VAR_LIB)/$(PRJ)/q_merge_requests
34 @-chown -R rocketgit:rocketgit $(I_VAR_LIB)/$(PRJ)
30 @mkdir -p --mode=0700 $(I_VAR_LOG)/$(PRJ)-web
31 @chown apache:apache $(I_VAR_LOG)/$(PRJ)-web
32 @mkdir -p --mode=0755 $(I_VAR_LIB)/$(PRJ)
33 @mkdir -p --mode=0700 $(I_VAR_LIB)/$(PRJ)/locks
34 @mkdir -p --mode=0755 $(I_VAR_LIB)/$(PRJ)/repos
35 @mkdir -p --mode=0700 $(I_VAR_LIB)/$(PRJ)/q_merge_requests
36 @mkdir -p --mode=0700 $(I_VAR_LIB)/$(PRJ)/qstats
37 @mkdir -p --mode=0755 $(I_VAR_LIB)/$(PRJ)/sockets
38 @chown -R rocketgit:rocketgit $(I_VAR_LIB)/$(PRJ)
File README changed (mode: 100644) (index f5ad10f..c9877b4)
77 77 . PHP . PHP
78 78 Adjust php.ini to allow enough RAM and execution time. Adjust php.ini to allow enough RAM and execution time.
79 79
80 . Mail
81 For sendmail, add rocketgit user to /etc/mail/trusted-users.
80 82
81 83 == Thanks == == Thanks ==
82 84 . Special thanks to my family that supported me in this project. . Special thanks to my family that supported me in this project.
File TODO changed (mode: 100644) (index 294792c..246d7d6)
1 1 == BEFORE FIRST RELEASE! == == BEFORE FIRST RELEASE! ==
2 [ ] http://joeyh.name/blog/entry/git_push_over_XMPP/ (ialbescu)
3 [ ] Checking mtime of event.php is not enough. Maybe checking version.
4 Think of includes that may change.
5 [ ] Create a unique index on users(username,organization)?
6 [ ] Do not allow duplicated ssh keys.
7 [ ] We have a little problem: we need the ssh keyring to regenerate fast but
8 we may have a big events queue. We may want to signal directly
9 the regeneration script and to not store mark-dirty state. Hm.
10 [ ] Optimize keyring invalidation.
11 [ ] Put "create user" on login page!
12 [ ] We should make stuff more robust. For example: CREATE REPO + HISTORY_INSERT.
13 [ ] What happens if we unlock an unlocked resource.
14 [ ] Renaming a repo!
15 If we move to numbers, and the names are links, we may have problems
16 when we create a repo with the same name.
17 If we just rename the folder, the current/future clients could not
18 access the repo. Maybe this is the best idea. If a user creates a
19 repo with the same name, this is life.
20 We have to record the renaming in the repo history.
21 [ ] What happends if a user is doing a downgrade? Must not allow it.
22 [ ] Use another home page for logged in users.
2 23 [ ] Check if same user can create two repos with the same name! [ ] Check if same user can create two repos with the same name!
3 24 [ ] When we are altering keys table and we upgrade, the file will not be rebuilt. [ ] When we are altering keys table and we upgrade, the file will not be rebuilt.
4 25 We have to dirty it. We have to dirty it.
 
37 58
38 59
39 60 == Medium == == Medium ==
61 [ ] Add history also for user.
62 [ ] template_table can deal with a FALSE para: load error.html file in list/
63 [ ] Put in history how many visitors received.
64 Maybe only whn hitting some limits?
65 [ ] Run shaX 1000 times for login?
66 [ ] There is no back button in tree browsing.
67 [ ] Allow users to have templates repo to be used when creating a new repo.
68 Also define global templates.
40 69 [ ] In logs we should log the version! [ ] In logs we should log the version!
41 70 [ ] GeoIP [ ] GeoIP
42 71 [ ] Specify a timeout for push/fetch. [ ] Specify a timeout for push/fetch.
File duilder.conf changed (mode: 100644) (index 532ad16..582263e)
1 1 PRJ="rocketgit" PRJ="rocketgit"
2 VER="0.15"
2 VER="0.16"
3 3 REV="1" REV="1"
4 4 EXCLUDE=".exclude" EXCLUDE=".exclude"
5 5 EXPORT_PATH="/data/www/umbrella/kernel/us/rocketgit" EXPORT_PATH="/data/www/umbrella/kernel/us/rocketgit"
File inc/bug.inc.php changed (mode: 100644) (index cdfc81a..11c5bc9)
... ... $rg_bug_error = "";
10 10 function rg_bug_set_error($str) function rg_bug_set_error($str)
11 11 { {
12 12 global $rg_bug_error; global $rg_bug_error;
13
14 13 $rg_bug_error = $str; $rg_bug_error = $str;
15 14 } }
16 15
File inc/events.inc.php added (mode: 100644) (index 0000000..bc8f557)
1 <?php
2 //
3 // This functions are used for background tasks: the tasks that the user should
4 // not wait to happen in the browser: e-mails, keyring regeneration etc.
5 //
6 require_once($INC . "/util.inc.php");
7 require_once($INC . "/log.inc.php");
8 require_once($INC . "/sql.inc.php");
9 require_once($INC . "/prof.inc.php");
10
11 if (!isset($rg_event_socket))
12 $rg_event_socket = "/var/lib/rocketgit/sockets/event.sock";
13
14 $rg_event_error = "";
15
16 function rg_event_set_error($str)
17 {
18 global $rg_event_error;
19 $rg_event_error = $str;
20 rg_log($str);
21 }
22
23 function rg_event_error()
24 {
25 global $rg_event_error;
26 return $rg_event_error;
27 }
28
29 $rg_event_split_functions = array();
30
31 /*
32 * Register event functions.
33 */
34 function rg_event_register_functions($functions)
35 {
36 global $rg_event_split_functions;
37
38 if (empty($functions)) {
39 rg_event_set_error("Cannot register empty array");
40 return FALSE;
41 }
42
43 foreach ($functions as $type => $function)
44 $rg_event_split_functions[$type] = $function;
45
46 return TRUE;
47 }
48
49 /*
50 * Signals the daemon that there is some work to do
51 */
52 function rg_event_signal_daemon()
53 {
54 global $rg_event_socket;
55
56 $ret = FALSE;
57 do {
58 $socket = socket_create(AF_UNIX, SOCK_DGRAM, 0);
59 if ($socket === FALSE) {
60 rg_log("Could not create socket!");
61 break;
62 }
63
64 $r = socket_connect($socket, $rg_event_socket);
65 if ($r === FALSE) {
66 rg_log("Could not connect the socket!");
67 break;
68 }
69
70 $buf = "W"; $len = strlen($buf);
71 $r = socket_send($socket, $buf, $len, 0);
72 if ($r !== $len) {
73 rg_log("Could not send!");
74 break;
75 }
76
77 socket_close($socket);
78 $ret = TRUE;
79 } while (0);
80
81 return $ret;
82 }
83
84 /*
85 * Inserts an event
86 * This function is called from all over the place to generate events
87 */
88 function rg_event_add($db, $event)
89 {
90 rg_prof_start("event_add");
91 rg_log("event_add: event=" . rg_array2string($event));
92
93 $ret = FALSE;
94 do {
95 $now = time();
96 $prio = $event['prio'];
97 $e_data = rg_sql_escape($db, serialize($event));
98 $sql = "INSERT INTO events (itime, prio, data)"
99 . " VALUES ($now, $prio, '$e_data')";
100 $res = rg_sql_query($db, $sql);
101 if ($res === FALSE) {
102 rg_event_set_error("Coulnd not add event (" . rg_sql_error() . ")");
103 break;
104 }
105 rg_sql_free_result($res);
106
107 rg_event_signal_daemon();
108
109 $ret = TRUE;
110 } while (0);
111
112 rg_prof_end("event_add");
113 return $ret;
114 }
115
116 /*
117 * Process an event
118 */
119 function rg_event_process($db, $event)
120 {
121 global $rg_event_split_functions;
122
123 rg_prof_start("event_process");
124 rg_log("event_process: event=" . rg_array2string($event));
125
126 $ret = FALSE;
127 do {
128 $category = $event['category'];
129 unset($event['category']);
130
131 if (!isset($rg_event_split_functions[$category])) {
132 rg_event_set_error("Cannot find event function [$category]!");
133 rg_log("DEBUG: rg_event_split_functions=" . rg_array2string($rg_event_split_functions));
134 break;
135 }
136
137 $f = $rg_event_split_functions[$category];
138 rg_log("Calling $f...");
139 $evs = $f($db, $event);
140 if ($evs === FALSE) {
141 rg_event_set_error("Failed to fill event for category [$category]!");
142 break;
143 }
144
145 if (empty($evs)) {
146 $ret = TRUE;
147 break;
148 }
149
150 $r = TRUE;
151 if (!is_array($evs))
152 rg_internal_error("evs is not array!");
153 foreach ($evs as $index => $ev) {
154 $r = rg_event_add($db, $ev);
155 if ($r !== TRUE)
156 break;
157 }
158 if ($r !== TRUE)
159 break;
160
161 $ret = TRUE;
162 } while (0);
163
164 rg_prof_end("event_process");
165 return $ret;
166 }
167
168 /*
169 * Process events queue
170 * reset id to 1 if queue is empty?
171 * Returns FALSE on error, else, the number of events processed
172 */
173 function rg_event_process_queue($db)
174 {
175 rg_prof_start("event_process_queue");
176 rg_log("event_process_queue");
177
178 $ret = FALSE;
179 $do_rollback = 0;
180 do {
181 $r = rg_sql_begin($db);
182 if ($r !== TRUE) {
183 rg_event_set_error("Cannot begin transaction"
184 . " (" . rg_sql_error() . ")");
185 break;
186 }
187 $do_rollback = 1;
188
189 // We limit to be able to deal with high prio tasks
190 $sql = "SELECT * FROM events"
191 . " ORDER BY prio, id"
192 . " FOR UPDATE"
193 . " LIMIT 100";
194 $res = rg_sql_query($db, $sql);
195 $no_of_events = rg_sql_num_rows($res);
196 if ($res === FALSE) {
197 rg_event_set_error("Cannot load job list"
198 . " (" . rg_sql_error() . ")");
199 break;
200 }
201
202 $r = TRUE;
203 while (($row = rg_sql_fetch_array($res))) {
204 $ev = unserialize($row['data']);
205 if ($ev === FALSE) {
206 rg_internal_error("Cannot unserialize data");
207 exit(1);
208 }
209 $r = rg_event_process($db, $ev);
210 if ($r !== TRUE)
211 break;
212
213 $sql = "DELETE FROM events WHERE id = " . $row['id'];
214 $res2 = rg_sql_query($db, $sql);
215 rg_sql_free_result($res2);
216 }
217 if ($r !== TRUE)
218 break;
219 rg_sql_free_result($res);
220
221 $r = rg_sql_commit($db);
222 if ($r !== TRUE)
223 break;
224
225 $ret = $no_of_events;
226 $do_rollback = 0;
227 } while (0);
228
229 if ($do_rollback == 1)
230 rg_sql_rollback($db);
231
232 rg_prof_end("event_process_queue");
233 return $ret;
234 }
235
236 ?>
File inc/git.inc.php changed (mode: 100644) (index c67035a..5cdbaab)
... ... $rg_git_error = "";
11 11 function rg_git_set_error($str) function rg_git_set_error($str)
12 12 { {
13 13 global $rg_git_error; global $rg_git_error;
14
15 14 $rg_git_error = $str; $rg_git_error = $str;
16 15 } }
17 16
File inc/keys.inc.php changed (mode: 100644) (index f0d9e7b..d994d30)
2 2 require_once($INC . "/sql.inc.php"); require_once($INC . "/sql.inc.php");
3 3 require_once($INC . "/state.inc.php"); require_once($INC . "/state.inc.php");
4 4 require_once($INC . "/prof.inc.php"); require_once($INC . "/prof.inc.php");
5 require_once($INC . "/events.inc.php");
5 6
6 7 $rg_keys_error = ""; $rg_keys_error = "";
7 8
8 9 function rg_keys_set_error($str) function rg_keys_set_error($str)
9 10 { {
10 11 global $rg_keys_error; global $rg_keys_error;
11
12 12 $rg_keys_error = $str; $rg_keys_error = $str;
13 13 } }
14 14
 
... ... function rg_keys_error()
18 18 return $rg_keys_error; return $rg_keys_error;
19 19 } }
20 20
21 /*
22 * Events functions
23 */
24 $rg_keys_functions = array(
25 1000 => "rg_keys_event_new",
26 1001 => "rg_keys_event_del",
27 1002 => "rg_keys_event_mark_dirty",
28 1003 => "rg_keys_event_notify_user"
29 );
30 rg_event_register_functions($rg_keys_functions);
31
32 /*
33 * Event for adding a new key
34 */
35 function rg_keys_event_new($db, $event)
36 {
37 $ret = array();
38
39 $event['op'] = "new";
40 // mark keys dirty
41 $ret[] = array_merge($event, array("category" => 1002, "prio" => 10));
42 // notify user
43 $ret[] = array_merge($event, array("category" => 1003, "prio" => 100));
44
45 return $ret;
46 }
47
48 /*
49 * Event for deleting a key
50 */
51 function rg_keys_event_del($db, $event)
52 {
53 $ret = array();
54 $event['type'] = 1;
55 $event['op'] = "del";
56 // mark keys dirty
57 $ret[] = array_merge($event, array("category" => 1002, "prio" => 10));
58 // notify user
59 $ret[] = array_merge($event, array("category" => 1003, "prio" => 100));
60 return $ret;
61 }
62
63 /*
64 * Notify user that a new key was added/deleted to/from the keyring
65 * TODO: Do not mark keys dirty from another place in this file
66 */
67 function rg_keys_event_mark_dirty($db, $event)
68 {
69 $r = rg_keys_mark_dirty($db);
70 if ($r === FALSE)
71 return FALSE;
72
73 return array();
74 }
75
76 /*
77 * Notify user that a new key was added to the keyring
78 */
79 function rg_keys_event_notify_user($db, $event)
80 {
81 rg_prof_start("keys_event_notify_user");
82 rg_log("keys_event_notify_user: event=" . rg_array2string($event));
83
84 // TODO: load info about the keys and put the fingerprint in e-mail
85 // TODO: Maybe put also the body in the e-mail, so it can be re-uploaded.
86 // TODO: Maybe add also the statistics.
87
88 $r = rg_mail("mail/user/key/" . $event['op'], $event);
89 if ($r === FALSE)
90 return FALSE;
91
92 rg_prof_end("keys_event_notify_user");
93 return array();
94 }
95
21 96 /* /*
22 97 * Extracts info about a ssh key * Extracts info about a ssh key
23 98 */ */
 
... ... function rg_keys_mark_dirty($db)
82 157
83 158 /* /*
84 159 * Remove a key from database * Remove a key from database
160 * TODO: Remove "multi" function and make this accepts an array of keys.
161 * TODO: Here we must have a transaction!
85 162 */ */
86 163 function rg_keys_remove($db, $rg_ui, $key_id, $flags) function rg_keys_remove($db, $rg_ui, $key_id, $flags)
87 164 { {
 
... ... function rg_keys_remove($db, $rg_ui, $key_id, $flags)
104 181 } }
105 182 rg_sql_free_result($res); rg_sql_free_result($res);
106 183
107 if (!isset($flags['no_dirty'])) {
108 if (rg_keys_mark_dirty($db) !== TRUE)
109 break;
184 $event = array("category" => 1001, "prio" => 50,
185 "email" => $rg_ui['email'],
186 "IP" => rg_var_str("REMOTE_ADDR"),
187 "key_id" => $key_id);
188 $r = rg_event_add($db, $event);
189 if ($r !== TRUE) {
190 rg_keys_set_error("cannot add event"
191 . " (" . rg_event_error() . ")");
192 break;
110 193 } }
111 194
112 195 $ret = TRUE; $ret = TRUE;
 
... ... function rg_keys_count($db, $uid)
176 259 /* /*
177 260 * Add a key * Add a key
178 261 * Returns the key_id of the key. * Returns the key_id of the key.
262 * TODO: Transaction!
179 263 */ */
180 264 function rg_keys_add($db, $rg_ui, $key) function rg_keys_add($db, $rg_ui, $key)
181 265 { {
 
... ... function rg_keys_add($db, $rg_ui, $key)
215 299 break; break;
216 300 } }
217 301 $row = rg_sql_fetch_array($res); $row = rg_sql_fetch_array($res);
218 $id = $row['key_id'];
302 $key_id = $row['key_id'];
219 303 rg_sql_free_result($res); rg_sql_free_result($res);
220 304
221 // set dirty
222 if (rg_keys_mark_dirty($db) != TRUE)
305 $event = array("category" => 1000, "prio" => 50,
306 "email" => $rg_ui['email'],
307 "IP" => rg_var_str("REMOTE_ADDR"),
308 "key_id" => $key_id);
309 $r = rg_event_add($db, $event);
310 if ($r !== TRUE) {
311 rg_keys_set_error("cannot add event"
312 . " (" . rg_event_error() . ")");
223 313 break; break;
314 }
224 315
225 $ret = $id;
316 $ret = $key_id;
226 317 } while (0); } while (0);
227 318
228 319 rg_prof_end("keys_add"); rg_prof_end("keys_add");
File inc/mr.inc.php changed (mode: 100644) (index cee6682..bdb91bf)
... ... $rg_mr_error = "";
15 15 function rg_mr_set_error($str) function rg_mr_set_error($str)
16 16 { {
17 17 global $rg_mr_error; global $rg_mr_error;
18
19 18 $rg_mr_error = $str; $rg_mr_error = $str;
20 19 } }
21 20
File inc/repo.inc.php changed (mode: 100644) (index 70f57e7..4d397ad)
... ... require_once($INC . "/user.inc.php");
6 6 require_once($INC . "/git.inc.php"); require_once($INC . "/git.inc.php");
7 7 require_once($INC . "/rights.inc.php"); require_once($INC . "/rights.inc.php");
8 8 require_once($INC . "/prof.inc.php"); require_once($INC . "/prof.inc.php");
9
10 $rg_repo_error = "";
9 require_once($INC . "/events.inc.php");
11 10
12 11 $rg_repo_rights = array( $rg_repo_rights = array(
13 12 "A" => "Admin", "A" => "Admin",
 
... ... $rg_repo_rights_default = "FMH";
34 33 rg_rights_register("repo", $rg_repo_rights); rg_rights_register("repo", $rg_repo_rights);
35 34
36 35
36 // Repo history categories
37 define('REPO_CAT_CREATE', 1);
38 define('REPO_CAT_CLONED', 2);
39 define('REPO_CAT_PUSH', 3);
40 define('REPO_CAT_RENAME', 4);
41 define('REPO_CAT_BUG_ADDED', 10);
42 define('REPO_CAT_BUG_CLOSED', 11);
43
44 $rg_repo_error = "";
45
37 46 function rg_repo_set_error($str) function rg_repo_set_error($str)
38 47 { {
39 48 global $rg_repo_error; global $rg_repo_error;
40
41 49 $rg_repo_error = $str; $rg_repo_error = $str;
42 50 } }
43 51
 
... ... function rg_repo_error()
47 55 return $rg_repo_error; return $rg_repo_error;
48 56 } }
49 57
58 /*
59 * Events functions
60 */
61 $rg_repo_functions = array(
62 3000 => "rg_repo_event_new",
63 3001 => "rg_repo_event_del",
64 3002 => "rg_repo_event_rename",
65 3003 => "rg_repo_event_notify_user"
66 );
67 rg_event_register_functions($rg_repo_functions);
68
69 /*
70 * Event for adding a new repo
71 */
72 function rg_repo_event_new($db, $event)
73 {
74 $ret = array();
75
76 $event['op'] = "new";
77 // notify user
78 $ret[] = array_merge($event, array("category" => 3003, "prio" => 100));
79 // TODO: notify watchers
80
81 return $ret;
82 }
83
84 /*
85 * Event for deleting repo
86 */
87 function rg_repo_event_del($db, $event)
88 {
89 $ret = array();
90
91 $event['op'] = "del";
92 // notify user
93 $ret[] = array_merge($event, array("category" => 3003, "prio" => 100));
94 // TODO: notify watchers
95
96 return $ret;
97 }
98
99 /*
100 * Event for renaming a repo
101 */
102 function rg_repo_event_rename($db, $event)
103 {
104 $ret = array();
105
106 $event['op'] = "rename";
107 // notify user
108 $ret[] = array_merge($event, array("category" => 3003, "prio" => 100));
109 // TODO: notify watchers
110
111 return $ret;
112 }
113
114 /*
115 * User notification
116 */
117 function rg_repo_event_notify_user($db, $event)
118 {
119 rg_prof_start("repo_event_notify_user");
120
121 $r = rg_mail("mail/user/repo/" . $event['op'], $event);
122 if ($r === FALSE)
123 return FALSE;
124
125 rg_prof_end("repo_event_notify_user");
126 return array();
127 }
128
129 /*
130 * Inserts an event into repo_history table
131 */
132 function rg_repo_history_insert($db, $repo_id, $category, $message)
133 {
134 rg_prof_start("repo_history_insert");
135 rg_log("repo_history_insert: repo_id=$repo_id, category=$category"
136 . ", message=$message");
137
138 $ret = FALSE;
139 do {
140 $now = time();
141 $e_message = rg_sql_escape($db, $message);
142 $sql = "INSERT INTO repo_history_" . gmdate("Y_m", $now)
143 . " (itime, repo_id, category, message)"
144 . " VALUES ($now, $repo_id, $category, '$e_message')";
145 $res = rg_sql_query($db, $sql);
146 if ($res === FALSE)
147 break;
148
149 rg_sql_free_result($res);
150 $ret = TRUE;
151 } while (0);
152
153 rg_prof_end("repo_history_insert");
154 return $ret;
155 }
156
157 /*
158 * Returns last events from repo_history
159 * @category: 0 for any
160 * @number: number of entries
161 * @max_seconds: limit the search to less than max_seconds in the past
162 */
163 function rg_repo_history_load($db, $repo_id, $category, $number, $max_seconds)
164 {
165 rg_prof_start("repo_history_load");
166 rg_log("repo_history_load: repo_id=$repo_id, category=$category"
167 . ", number=$number max_seconds=$max_seconds");
168
169 $ret = FALSE;
170 do {
171 $now = time();
172
173 $category_sql = "";
174 if ($category > 0)
175 $category_sql = " AND category = " . $category;
176
177 $limit_sql = "";
178 if ($number > 0)
179 $limit_sql = " LIMIT " . $number;
180 else
181 $limit_sql = " LIMIT 100";
182
183 $time_sql = "";
184 if ($max_seconds > 0)
185 $time_sql = " AND itime >= " . ($now - $max_seconds);
186
187 $sql = "SELECT * FROM repo_history"
188 . " WHERE repo_id = $repo_id"
189 . $category_sql
190 . $time_sql
191 . " ORDER BY itime DESC"
192 . $limit_sql;
193 $res = rg_sql_query($db, $sql);
194 if ($res === FALSE)
195 break;
196
197 $ret = array();
198 while (($row = rg_sql_fetch_array($res))) {
199 $row['itime_text'] = gmdate("Y-m-d H:i", $row['itime']);
200 $ret[] = $row;
201 }
202
203 rg_sql_free_result($res);
204 } while (0);
205
206 rg_prof_end("repo_history_load");
207 return $ret;
208 }
209
50 210 /* /*
51 211 * Enforce name * Enforce name
52 212 */ */
 
... ... function rg_repo_create($db, $master, $rg_ui, $name, $max_commit_size,
275 435 break; break;
276 436 } }
277 437 $row = rg_sql_fetch_array($res); $row = rg_sql_fetch_array($res);
278 $ret = $row['repo_id'];
279 438 rg_sql_free_result($res); rg_sql_free_result($res);
439
440 $event = array("category" => 3000, "prio" => 50,
441 "name" => $name,
442 "description" => $description,
443 "rights" => implode("\n", rg_rights_text("repo", $rights)),
444 "email" => $rg_ui['email'],
445 "IP" => rg_var_str("REMOTE_ADDR"),
446 "repo_id" => $row['repo_id']);
447 $r = rg_event_add($db, $event);
448 if ($r !== TRUE) {
449 rg_repo_set_error("cannot add event"
450 . " (" . rg_event_error() . ")");
451 break;
452 }
453
454 // TODO: This will go with events
455 rg_repo_history_insert($db, $row['repo_id'], REPO_CAT_CREATE,
456 "Repo " . $name . " created.");
457
458 $ret = $row['repo_id'];
280 459 } while (0); } while (0);
281 460
282 461 // git repo creation will be delayed for serialization reasons // git repo creation will be delayed for serialization reasons
File inc/rights.inc.php changed (mode: 100644) (index ca76c1a..90aa7bb)
... ... $rg_rights_error = "";
14 14 function rg_rights_set_error($str) function rg_rights_set_error($str)
15 15 { {
16 16 global $rg_rights_error; global $rg_rights_error;
17
18 17 $rg_rights_error = $str; $rg_rights_error = $str;
19 18 } }
20 19
File inc/sql.inc.php changed (mode: 100644) (index e3a7ac5..dbbd92b)
2 2 require_once($INC . "/log.inc.php"); require_once($INC . "/log.inc.php");
3 3 require_once($INC . "/prof.inc.php"); require_once($INC . "/prof.inc.php");
4 4
5 if (!function_exists("pg_connect"))
6 die("FATAL: php PostgreSQL is not installed!");
7
5 8 $rg_sql_conn = array(); $rg_sql_conn = array();
6 9
7 10 $rg_sql_error = ""; $rg_sql_error = "";
8 11
9 if (!function_exists("pg_connect"))
10 die("FATAL: php PostgreSQL is not installed!");
11
12 12 /* /*
13 13 * Set error string * Set error string
14 14 */ */
15 15 function rg_sql_set_error($str) function rg_sql_set_error($str)
16 16 { {
17 17 global $rg_sql_error; global $rg_sql_error;
18
19 18 $rg_sql_error = $str; $rg_sql_error = $str;
20 19 } }
21 20
22 21 function rg_sql_error() function rg_sql_error()
23 22 { {
24 23 global $rg_sql_error; global $rg_sql_error;
25
26 24 return $rg_sql_error; return $rg_sql_error;
27 25 } }
28 26
File inc/state.inc.php changed (mode: 100644) (index 021200d..3cd1821)
1 1 <?php <?php
2 2 require_once($INC . "/sql.inc.php"); require_once($INC . "/sql.inc.php");
3 3
4 $rg_state_error = "";
5
4 6 function rg_state_set_error($str) function rg_state_set_error($str)
5 7 { {
6 8 global $rg_state_error; global $rg_state_error;
7
8 9 $rg_state_error = $str; $rg_state_error = $str;
9 10 } }
10 11
File inc/struct.inc.php changed (mode: 100644) (index dccf574..51d8064)
... ... include_once($INC . "/util.inc.php");
6 6 define("RG_DROP_TABLES", 1); define("RG_DROP_TABLES", 1);
7 7 define("RG_IGNORE_ERRORS", 1 << 1); define("RG_IGNORE_ERRORS", 1 << 1);
8 8
9 $rg_sql_struct_slaves = array();
9 10 $rg_sql_struct = array(); $rg_sql_struct = array();
10 11 $rg_sql_struct[1] = array(); $rg_sql_struct[1] = array();
11 12 $rg_sql_struct[1]['tables'] = array( $rg_sql_struct[1]['tables'] = array(
 
... ... $rg_sql_struct[9] = array();
192 193 $rg_sql_struct[9]['tables'] = array(); $rg_sql_struct[9]['tables'] = array();
193 194 $rg_sql_struct[9]['other'] = array( $rg_sql_struct[9]['other'] = array(
194 195 "allow duplicate ssh keys" => "ALTER TABLE keys" "allow duplicate ssh keys" => "ALTER TABLE keys"
195 . " DROP CONSTRAINT IF EXISTS keys_key_key",
196 . " DROP CONSTRAINT IF EXISTS keys_pkey",
197 "index on key_id" => "CREATE INDEX keys_i_key_id"
198 . " ON keys(key_id)",
196 199 "allow duplicate repos names" => "ALTER TABLE repos" "allow duplicate repos names" => "ALTER TABLE repos"
197 . " DROP CONSTRAINT IF EXISTS repos_name_key",
198 "index on repos names" => "CREATE INDEX repos_i_name ON repos(name)"
200 . " DROP CONSTRAINT IF EXISTS repos_pkey",
201 "index on repos names" => "CREATE INDEX repos_i_name"
202 . " ON repos(name)"
199 203 ); );
200 204
205 $rg_sql_struct[10] = array();
206 $rg_sql_struct[10]['tables'] = array(
207 "repo_history" => "CREATE TABLE repo_history ("
208 . "itime INT NOT NULL"
209 . ", repo_id INT NOT NULL"
210 . ", category SMALLINT NOT NULL"
211 . ", message TEXT NOT NULL)"
212 );
213 $rg_sql_struct[10]['other'] = array();
214 $rg_sql_struct_slaves['repo_history'] = "repo_history";
215
216 $rg_sql_struct[11] = array();
217 $rg_sql_struct[11]['tables'] = array(
218 "repo_history" => "CREATE TABLE events ("
219 . "id BIGSERIAL PRIMARY KEY"
220 . ", itime INT NOT NULL"
221 . ", type INT NOT NULL"
222 . ", data TEXT NOT NULL)"
223 );
224 $rg_sql_struct[11]['other'] = array();
225
226 $rg_sql_struct[12] = array();
227 $rg_sql_struct[12]['tables'] = array(
228 "index on uid" => "CREATE INDEX repos_i_uid ON repos(uid)",
229 "index on repo_id" => "CREATE INDEX repos_i_repo_id ON repos(repo_id)"
230 );
231 $rg_sql_struct[12]['other'] = array();
232
201 233
202 234 // This must be the last line // This must be the last line
203 235 $rg_sql_schema_ver = count($rg_sql_struct); $rg_sql_schema_ver = count($rg_sql_struct);
 
... ... function rg_sql_struct_update($db, $flags)
337 369
338 370 return $ret; return $ret;
339 371 } }
372
373 /*
374 * Update slaves (postgresql partitions)
375 * Returns FALSE in case of error
376 */
377 function rg_sql_struct_slaves_update($db)
378 {
379 global $rg_sql_struct_slaves;
380
381 rg_prof_start("sql_struct_slaves_update");
382 rg_log("sql_struct_update");
383
384 $ret = FALSE;
385 $rollback = 0;
386 do {
387 if (empty($rg_sql_struct_slaves)) {
388 $ret = TRUE;
389 break;
390 }
391
392 $last_ts = rg_state_get($db, "slaves_create_last_ts");
393 if ($last_ts === FALSE)
394 break;
395
396 $last_ts = intval($last_ts);
397 if ($last_ts == 0)
398 $last_ts = gmmktime(0, 0, 0, gmdate("m"), 1, gmdate("Y"));
399
400 // First second of next month
401 $next_month_ts = gmmktime(0, 0, 0, gmdate("m") + 1, gmdate("d"), gmdate("Y"));
402
403 if ($next_month_ts == $last_ts) {
404 rg_log(" No update needed!");
405 $ret = TRUE;
406 break;
407 }
408
409 // If we cannot lock, return error
410 if (rg_lock("slave_create.lock") === FALSE)
411 return FALSE;
412
413 if (rg_sql_begin($db) !== TRUE)
414 break;
415 $rollback = 1;
416
417 $ok = TRUE;
418 $month = gmdate("m", $last_ts);
419 $year = gmdate("Y", $last_ts);
420 $ts = gmmktime(0, 0, 0, $month, 1, $year);
421 do {
422 $month++;
423 $next_ts = gmmktime(0, 0, 0, $month, 1, $year);
424
425 foreach ($rg_sql_struct_slaves as $table) {
426 $slave_table = $table . "_" . gmdate("Y", $ts) . "_" . gmdate("m", $ts);
427 $sql = "CREATE TABLE " . $slave_table
428 . " (CHECK(itime >= $ts AND itime <= " . ($next_ts - 1) . "))"
429 . " INHERITS (" . $table . ")";
430 $res = rg_sql_query($db, $sql);
431 if ($res === FALSE) {
432 $ok = FALSE;
433 break;
434 }
435 rg_sql_free_result($res);
436
437 $sql = "CREATE INDEX " . $slave_table . "_i_itime"
438 . " ON " . $slave_table
439 . " (itime)";
440 $res = rg_sql_query($db, $sql);
441 if ($res === FALSE) {
442 $ok = FALSE;
443 break;
444 }
445 rg_sql_free_result($res);
446 }
447 $ts = $next_ts;
448 } while ($ts < $next_month_ts);
449 if ($ok === FALSE)
450 break;
451
452 $r = rg_state_set($db, "slaves_create_last_ts", $next_month_ts);
453 if ($r !== TRUE) {
454 rg_log("Cannot create slave (" . rg_state_error() . ")");
455 break;
456 }
457
458 if (rg_sql_commit($db) !== TRUE)
459 break;
460
461 $rollback = 0;
462 $ret = TRUE;
463 } while (0);
464
465 if ($rollback == 1)
466 rg_sql_rollback($db);
467
468 rg_unlock("slave_create.lock");
469
470 rg_prof_end("sql_struct_slaves_update");
471 return $ret;
472 }
340 473 ?> ?>
File inc/token.inc.php changed (mode: 100644) (index f4193c4..2d3eb1b)
... ... $rg_token_error = "";
8 8 function rg_token_set_error($str) function rg_token_set_error($str)
9 9 { {
10 10 global $rg_token_error; global $rg_token_error;
11
12 11 $rg_token_error = $str; $rg_token_error = $str;
13 12 } }
14 13
File inc/user.inc.php changed (mode: 100644) (index 26ff599..9248762)
... ... require_once($INC . "/log.inc.php");
4 4 require_once($INC . "/sql.inc.php"); require_once($INC . "/sql.inc.php");
5 5 require_once($INC . "/sess.inc.php"); require_once($INC . "/sess.inc.php");
6 6 require_once($INC . "/rights.inc.php"); require_once($INC . "/rights.inc.php");
7 require_once($INC . "/events.inc.php");
7 8
8 9 $rg_user_rights = array( $rg_user_rights = array(
9 10 "C" => "Create repositories", "C" => "Create repositories",
 
... ... $rg_user_rights = array(
12 13
13 14 rg_rights_register("user", $rg_user_rights); rg_rights_register("user", $rg_user_rights);
14 15
16 $rg_user_error = "";
17
15 18 function rg_user_set_error($str) function rg_user_set_error($str)
16 19 { {
17 global $_rg_user_error;
18
19 $_rg_user_error = $str;
20 global $rg_user_error;
21 $rg_user_error = $str;
20 22 } }
21 23
22 24 function rg_user_error() function rg_user_error()
23 25 { {
24 global $_rg_user_error;
25 return $_rg_user_error;
26 global $rg_user_error;
27 return $rg_user_error;
28 }
29
30 /*
31 * Event functions
32 */
33 $rg_user_functions = array(
34 2000 => "rg_user_event_new",
35 2002 => "rg_user_event_notify_user"
36 );
37 rg_event_register_functions($rg_user_functions);
38
39 /*
40 * Event for adding a new user
41 */
42 function rg_user_event_new($db, $event)
43 {
44 $ret = array();
45
46 $event['op'] = "new";
47 // notify user
48 $ret[] = array_merge($event, array("category" => 2002, "prio" => 100));
49
50 return $ret;
51 }
52
53 /*
54 * Notify user: welcome
55 */
56 function rg_user_event_notify_user($db, $event)
57 {
58 rg_log("user_event_notify_user: event=" . rg_array2string($event));
59
60 $r = rg_mail("mail/user/welcome", $event);
61 if ($r === FALSE)
62 return FALSE;
63
64 return array();
26 65 } }
27 66
28 67 /* /*
 
... ... function rg_user_edit($db, $d)
181 220 // invalidate cache // invalidate cache
182 221 $rg_user_info_cache = array(); $rg_user_info_cache = array();
183 222
223 if ($d['uid'] == 0) { // add
224 $event = array("category" => 2000, "prio" => 50,
225 "email" => $d['email']
226 );
227 $r = rg_event_add($db, $event);
228 if ($r === FALSE) {
229 rg_user_set_error("Canot add event!");
230 return FALSE;
231 }
232 }
233
184 234 return TRUE; return TRUE;
185 235 } }
186 236
File inc/user/repo-page.php changed (mode: 100644) (index db81318..ddb649e)
... ... $repo_dir = rg_repo_name2base($rr) . $rr['repo'] . ".git";
67 67 rg_log("repo_dir=$repo_dir"); rg_log("repo_dir=$repo_dir");
68 68 putenv("GIT_DIR=$repo_dir"); putenv("GIT_DIR=$repo_dir");
69 69
70 // default is "source" tab
71 if (empty($subop))
72 $subop = "source";
73
74 70 $repo_more['repo_body'] = ""; $repo_more['repo_body'] = "";
75 71 $repo_more['repo_right'] = ""; $repo_more['repo_right'] = "";
76 72 $repo_more['branches_and_tags'] = ""; $repo_more['branches_and_tags'] = "";
 
... ... if ($rg_git_port != 0)
85 81 $urls[]['HTML:url'] = '<a href="' . $repo_more['git'] . '">' . $repo_more['git'] . '</a>'; $urls[]['HTML:url'] = '<a href="' . $repo_more['git'] . '">' . $repo_more['git'] . '</a>';
86 82 $repo_more['HTML:urls'] = rg_template_table("repo/urls", $urls, $repo_more); $repo_more['HTML:urls'] = rg_template_table("repo/urls", $urls, $repo_more);
87 83
88 if (strcmp($subop, "admin") == 0) {
84 // default is "source" tab
85 if (empty($subop))
86 $subop = "history";
87
88 if (strcmp($subop, "history") == 0) {
89 $hist = rg_repo_history_load($db, $ri['repo_id'], 0, 20, 0);
90 if ($hist === FALSE)
91 $_repo_body .= rg_warning("Cannot load history. Try again later.");
92 else
93 $_repo_body .= rg_template_table("repo/history", $hist, $repo_more);
94 } else if (strcmp($subop, "admin") == 0) {
89 95 include($INC . "/user/repo/admin/admin.php"); include($INC . "/user/repo/admin/admin.php");
90 96 $_repo_body .= $_admin; $_repo_body .= $_admin;
91 97 } else if (strcmp($subop, "source") == 0) { } else if (strcmp($subop, "source") == 0) {
File inc/util.inc.php changed (mode: 100644) (index 2ad030f..30d9412)
... ... require_once($INC . "/log.inc.php");
5 5 set_error_handler("rg_error_handler"); set_error_handler("rg_error_handler");
6 6 register_shutdown_function("rg_shutdown_error"); register_shutdown_function("rg_shutdown_error");
7 7
8 $rg_util_error = "";
9
8 10 function rg_util_set_error($str) function rg_util_set_error($str)
9 11 { {
10 global $_rg_util_error;
11 $_rg_util_error = $str;
12 global $rg_util_error;
13 $rg_util_error = $str;
12 14 } }
13 15
14 16 function rg_util_error() function rg_util_error()
15 17 { {
16 global $_rg_util_error;
17 return $_rg_util_error;
18 global $rg_util_error;
19 return $rg_util_error;
18 20 } }
19 21
20 22 function rg_1024($v) function rg_1024($v)
 
... ... function rg_unlock($file)
102 104 { {
103 105 global $_lock; global $_lock;
104 106
105 fclose($_lock[$file]);
107 if (isset($_lock[$file]))
108 fclose($_lock[$file]);
106 109 } }
107 110
108 111 function rg_load() function rg_load()
 
... ... function rg_var_str($name)
211 214 { {
212 215 $ret = ""; $ret = "";
213 216
214 if (isset($_COOKIE[$name]))
217 if (isset($_SERVER[$name]))
218 $ret = $_SERVER[$name];
219 else if (isset($_COOKIE[$name]))
215 220 $ret = $_COOKIE[$name]; $ret = $_COOKIE[$name];
216 221 else if (isset($_POST[$name])) else if (isset($_POST[$name]))
217 222 $ret = $_POST[$name]; $ret = $_POST[$name];
 
... ... function rg_prepare_replace(&$data, &$what, &$values)
532 537 */ */
533 538 function rg_file_get_contents($f) function rg_file_get_contents($f)
534 539 { {
535 if (!file_exists($f))
540 if (!file_exists($f)) {
541 rg_log("File $f does not exists.");
536 542 return ""; return "";
543 }
537 544
538 545 return @file_get_contents($f); return @file_get_contents($f);
539 546 } }
 
... ... function rg_template_table($dir, $data, $more)
547 554 global $rg_scripts; global $rg_scripts;
548 555
549 556 $xdir = $rg_scripts . "/root/themes/" . $rg_theme . "/" . $dir; $xdir = $rg_scripts . "/root/themes/" . $rg_theme . "/" . $dir;
550 if (!is_dir($xdir))
557 if (!is_dir($xdir)) {
558 rg_log("$xdir not found.");
551 559 $xdir = $rg_scripts . "/root/themes/default/" . $dir; $xdir = $rg_scripts . "/root/themes/default/" . $dir;
560 rg_log("Using [$xdir]");
561 }
552 562
553 563 $m_what = array(); $m_values = array(); $m_what = array(); $m_values = array();
554 564 rg_prepare_replace($more, $m_what, $m_values); rg_prepare_replace($more, $m_what, $m_values);
 
... ... function rg_date2ts_last_second($s)
951 961 return gmmktime(0, 0, 0, $f[1], $f[2] + 1, $f[0]) - 1; return gmmktime(0, 0, 0, $f[1], $f[2] + 1, $f[0]) - 1;
952 962 } }
953 963
964 /*
965 * Function to send e-mails
966 * TODO: Replace mail() wil rg_mail everywhere.
967 */
968 function rg_mail($template, $more)
969 {
970 global $rg_admin_name, $rg_admin_email;
971
972 rg_prof_start("mail");
973 rg_log("mail: $template, more=" . rg_array2string($more));
974
975
976 $more['HTML:rg_admin_email'] = $rg_admin_email;
977 $more['HTML:utf8_rg_admin_name'] = "=?UTF-8?B?"
978 . base64_encode($rg_admin_name) . "?=";
979
980 $subject = rg_template($template . ".subj.txt", $more);
981 $subject = "=?UTF-8?B?" . base64_encode(trim($subject)) . "?=";
982 $header = rg_template($template . ".head.txt", $more);
983 $body = rg_template($template . ".body.txt", $more);
984
985 $ret = mail($more['email'], $subject, $body, $header, "-f $rg_admin_email");
986 if ($ret === FALSE)
987 rg_log("Sending mail failed!");
988
989 rg_prof_end("mail");
990 return $ret;
991 }
992
954 993 ?> ?>
File inc/ver.php.in changed (mode: 100644) (index 32beda9..848a351)
1 1 <?php <?php
2 // WARNING: This file is autogenerated from ver.php.in. Do not modify it.
3
2 4
3 5 $rocketgit_version = "@VER@-@REV@"; $rocketgit_version = "@VER@-@REV@";
4 6
File rocketgit.spec.in changed (mode: 100644) (index a47d6af..ca06a83)
... ... rm -rf ${RPM_BUILD_ROOT}
51 51
52 52 %files %files
53 53 %attr (-,root,root) %attr (-,root,root)
54 @USR_SHARE@/@PRJ@
55 %doc README LICENSE Changelog TODO
56 %dir /etc/@PRJ@
57 %config(noreplace) /etc/@PRJ@/config.php
58 /etc/@PRJ@/config.php.sample
59 /etc/cron.d/rocketgit
60 %config(noreplace) /etc/xinetd.d/rocketgit
61 %config(noreplace) /etc/httpd/conf.d/rocketgit.conf
62 %attr(0700,rocketgit,rocketgit) %dir /var/log/@PRJ@
63 %attr(0700,apache,apache) %dir /var/log/@PRJ@-web
64 %attr(0755,rocketgit,rocketgit) %dir /var/lib/@PRJ@
65 %attr(0700,rocketgit,rocketgit) %dir /var/lib/@PRJ@/locks
66 %attr(0755,rocketgit,rocketgit) %dir /var/lib/@PRJ@/repos
67 %attr(0700,rocketgit,rocketgit) %dir /var/lib/@PRJ@/q_merge_requests
68 %config(noreplace) /etc/logrotate.d/rocketgit
54 %attr(0755,root,root) %dir @USR_SHARE@/@PRJ@
55 %attr(0755,root,root) %doc README LICENSE Changelog TODO
56 %attr(0755,root,root) %dir @ETC@/@PRJ@
57 %attr(0755,root,root) %config(noreplace) @ETC@/@PRJ@/config.php
58 %attr(0755,root,root) @ETC@/@PRJ@/config.php.sample
59 %attr(0755,root,root) @ETC@/cron.d/rocketgit
60 %attr(0755,roor,root) %config(noreplace) @ETC@/xinetd.d/rocketgit
61 %attr(0755,root,root) %config(noreplace) @ETC@/httpd/conf.d/rocketgit.conf
62 %attr(0755,root,root) %config(noreplace) @ETC@/logrotate.d/rocketgit
63 %attr(0700,rocketgit,rocketgit) %dir @VAR_LOG@/@PRJ@
64 %attr(0700,apache,apache) %dir @VAR_LOG@/@PRJ@-web
65 %attr(0755,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@
66 %attr(0700,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/locks
67 %attr(0755,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/repos
68 %attr(0700,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/q_merge_requests
69 %attr(0755,rocketgit,rocketgit) %dir @VAR_LIB@/@PRJ@/sockets
69 70
70 71 %changelog %changelog
71 72 * Wed Oct 17 2012 Catalin(ux) M. BOIE <catab at embedromix dor ro> 0.10 * Wed Oct 17 2012 Catalin(ux) M. BOIE <catab at embedromix dor ro> 0.10
File root/index.php changed (mode: 100644) (index 03d0592..9a4ac39)
... ... while (1) {
98 98 if ($r === FALSE) if ($r === FALSE)
99 99 break; break;
100 100
101 echo "Schema is not up-to-date! Sleep 1 second...";
101 rg_log("Schema is not up-to-date! Sleep 1 second...");
102 102 sleep(1); sleep(1);
103 103 } }
104 104
File root/themes/default/index.html changed (mode: 100644) (index 5a9fa5a..e6108d0)
52 52 <td> <td>
53 53 Copyright: <a href="http://kernel.embedromix.ro/">Catalin(ux) M. BOIE</a><br /> Copyright: <a href="http://kernel.embedromix.ro/">Catalin(ux) M. BOIE</a><br />
54 54 Version: @@rg_version@@<br /> Version: @@rg_version@@<br />
55 Install date: @@first_install_text@@
55 Running since: @@first_install_text@@
56 56 </td> </td>
57 57 </tr> </tr>
58 58 </tbody> </tbody>
File root/themes/default/mail/user/key/del.body.txt added (mode: 100644) (index 0000000..0bd1a33)
1 Hello!
2
3 A SSH key was removed from your account.
4
5 IP: @@IP@@
6
7 Thank you!
8
9 --
10 RocketGit Team
11 http://rocketgit.net
File root/themes/default/mail/user/key/del.head.txt added (mode: 100644) (index 0000000..8f86db1)
1 From: @@utf8_rg_admin_name@@ <@@rg_admin_email@@>
2 MIME-Version: 1.0
3 Content-type: text/plain; charset=UTF-8
File root/themes/default/mail/user/key/del.subj.txt added (mode: 100644) (index 0000000..1a4c997)
1 A SSH key was removed
File root/themes/default/mail/user/key/new.body.txt added (mode: 100644) (index 0000000..09259a6)
1 Hello!
2
3 A new SSH key was added to your account.
4
5 IP: @@IP@@
6
7 Thank you!
8
9 --
10 RocketGit Team
11 http://rocketgit.net
File root/themes/default/mail/user/key/new.head.txt added (mode: 100644) (index 0000000..8f86db1)
1 From: @@utf8_rg_admin_name@@ <@@rg_admin_email@@>
2 MIME-Version: 1.0
3 Content-type: text/plain; charset=UTF-8
File root/themes/default/mail/user/key/new.subj.txt added (mode: 100644) (index 0000000..1663e59)
1 New SSH key added
File root/themes/default/mail/user/repo/new.body.txt added (mode: 100644) (index 0000000..1dd9740)
1 Hello!
2
3 Repo '@@name@@' was created.
4
5 Anonymous rights:
6 @@rights@@
7
8 Description:
9 @@description@@
10
11 IP: @@IP@@
12
13 Thank you!
14
15 --
16 RocketGit Team
17 http://rocketgit.net
File root/themes/default/mail/user/repo/new.head.txt added (mode: 100644) (index 0000000..8f86db1)
1 From: @@utf8_rg_admin_name@@ <@@rg_admin_email@@>
2 MIME-Version: 1.0
3 Content-type: text/plain; charset=UTF-8
File root/themes/default/mail/user/repo/new.subj.txt added (mode: 100644) (index 0000000..21bd798)
1 '@@name@@' repo was created
File root/themes/default/mail/user/welcome.body.txt added (mode: 100644) (index 0000000..eb3918f)
1 Hello!
2
3 Welcome to RocketGit!
4
5 We will gladly host your projects.
6 Enjoy your stay!
7
8 Thank you!
9
10 --
11 RocketGit Team
12 http://rocketgit.net
File root/themes/default/mail/user/welcome.head.txt added (mode: 100644) (index 0000000..8f86db1)
1 From: @@utf8_rg_admin_name@@ <@@rg_admin_email@@>
2 MIME-Version: 1.0
3 Content-type: text/plain; charset=UTF-8
File root/themes/default/mail/user/welcome.subj.txt added (mode: 100644) (index 0000000..e86497f)
1 Welcome to RocketGit!
File root/themes/default/repo/history/header.html changed (mode: 100644) (index 3ff0e3d..9027dc6)
1 <div class="page_title">History</div>
2 1 <table> <table>
3 <tr>
4 <th>Date (UTC)</th>
5 <th>Text</th>
6 </tr>
7
File root/themes/default/repo/history/line.html changed (mode: 100644) (index 065d6c2..5efd58c)
1 1 <tr> <tr>
2 2 <td>@@itime_text@@</td> <td>@@itime_text@@</td>
3 <td>@@text@@</td>
3 <td>@@message@@</td>
4 4 </tr> </tr>
File root/themes/default/repo/main.html changed (mode: 100644) (index 1f60940..66b827b)
13 13
14 14 <div class="menu submenu"> <div class="menu submenu">
15 15 <ul> <ul>
16 <li><a href="@@url_repo@@/history">History</a></li>
16 17 <li><a href="@@url_repo@@/source">Source</a></li> <li><a href="@@url_repo@@/source">Source</a></li>
17 18 <li><a href="@@url_repo@@/mr">Merge requests</a></li> <li><a href="@@url_repo@@/mr">Merge requests</a></li>
18 19 <li><a href="@@url_repo@@/bug">Bugs</a></li> <li><a href="@@url_repo@@/bug">Bugs</a></li>
File samples/cron changed (mode: 100644) (index e52cfd9..85fa189)
1 1 * * * * * rocketgit php /usr/share/rocketgit/scripts/cron.php * * * * * rocketgit php /usr/share/rocketgit/scripts/cron.php
2 2 * * * * * rocketgit php /usr/share/rocketgit/scripts/q.php * * * * * rocketgit php /usr/share/rocketgit/scripts/q.php
3 * * * * * rocketgit php /usr/share/rocketgit/scripts/events.php
File scripts/cron.php changed (mode: 100644) (index 50a58d8..0acf8f8)
... ... $r = rg_sql_struct_update($db, 0);
33 33 if ($r !== TRUE) if ($r !== TRUE)
34 34 exit(1); exit(1);
35 35
36 if (date("H") == 0) {
36 if (date("H") == 4) {
37 37 rg_log("Compute repository sizes if dirty..."); rg_log("Compute repository sizes if dirty...");
38 38 // delete 'dirty' files // delete 'dirty' files
39 39 $sql = "SELECT a.*, b.username, b.organization" $sql = "SELECT a.*, b.username, b.organization"
 
... ... if (date("H") == 0) {
89 89 // TODO // TODO
90 90 //rg_log("Sending notifications..."); //rg_log("Sending notifications...");
91 91
92 if (date("H") == 0) {
92 if (date("H") == 3) {
93 93 rg_log("Clean old forget_pass entries..."); rg_log("Clean old forget_pass entries...");
94 94 $sql = "DELETE FROM forgot_pass WHERE expire < $now"; $sql = "DELETE FROM forgot_pass WHERE expire < $now";
95 95 $res = rg_sql_query($db, $sql); $res = rg_sql_query($db, $sql);
 
... ... if (date("H") == 1) {
110 110 rg_sql_free_result($res); rg_sql_free_result($res);
111 111 } }
112 112
113 if (date("H") == 2)
114 rg_sql_struct_slaves_update($db);
115
113 116 rg_keys_regen($db); rg_keys_regen($db);
114 117
115 118 // Arhive deleted repositories // Arhive deleted repositories
File scripts/events.php added (mode: 100644) (index 0000000..5553891)
1 <?php
2 // This is called by cron, and is persistent.
3 // It takes care of any background job received.
4 // It will receive signals using a UNIX socket.
5 // TODO: This will obsolete q.php
6 error_reporting(E_ALL);
7 ini_set("track_errors", "On");
8
9 $now = time();
10 $_s = microtime(TRUE);
11
12 require_once("/etc/rocketgit/config.php");
13
14 $INC = dirname(__FILE__) . "/../inc";
15 require_once($INC . "/init.inc.php");
16 require_once($INC . "/log.inc.php");
17 require_once($INC . "/sql.inc.php");
18 require_once($INC . "/struct.inc.php");
19 require_once($INC . "/events.inc.php");
20 require_once($INC . "/repo.inc.php");
21 require_once($INC . "/prof.inc.php");
22 require_once($INC . "/mr.inc.php");
23 require_once($INC . "/keys.inc.php");
24 require_once($INC . "/user.inc.php");
25
26 rg_prof_start("MAIN");
27
28 rg_log_set_file($rg_log_dir . "/events.log");
29
30 // locking
31 rg_lock_or_exit("events.lock");
32
33 rg_log("Start...");
34
35 $db = rg_sql_open($rg_sql);
36 if ($db === FALSE) {
37 rg_internal_error("Cannot connect to database!");
38 // TODO: inform admin - already by e-mail?
39 exit(1);
40 }
41
42 $r = rg_sql_struct_update($db, 0);
43 if ($r !== TRUE)
44 exit(1);
45
46 // Remove the socket, else we will get error
47 if (file_exists($rg_event_socket))
48 unlink($rg_event_socket);
49
50 // Prepare socket for signaling
51 $socket = socket_create(AF_UNIX, SOCK_DGRAM, 0);
52 if ($socket === FALSE) {
53 rg_internal_error("Cannot create events socket!");
54 exit(1);
55 }
56
57 $r = socket_bind($socket, $rg_event_socket);
58 if ($r === FALSE) {
59 rg_internal_error("Cannot bind socket!");
60 exit(1);
61 }
62
63 // Allow apache to connect to socket
64 $r = chmod($rg_event_socket, 0666);
65 if ($r === FALSE) {
66 rg_internal_error("Cannot set rights on event socket!");
67 exit(1);
68 }
69
70 $original_mtime = filemtime(__FILE__);
71 do {
72 // Check our mtime so we can upgrade the software and this script
73 // will restart.
74 clearstatcache();
75 $mtime = filemtime(__FILE__);
76 rg_log("mtime=$mtime, original_mtime=$original_mtime");
77 if ($mtime != $original_mtime) {
78 rg_log("File changed. Exiting...");
79 break;
80 }
81
82 // check machine load - if too big we will delay
83 $load = rg_load();
84 if ($load > 10) {
85 rg_log("\tLoad too big!");
86 sleep(10);
87 continue;
88 }
89
90 do {
91 $r = rg_event_process_queue($db);
92 if ($r === FALSE)
93 break;
94 } while ($r > 0);
95 if ($r === FALSE)
96 break;
97
98 // Wait for signal
99 rg_log("Waiting for signal...");
100 socket_recvfrom($socket, $buf, 1024, 0, $from);
101 } while (1);
102
103 socket_close($socket);
104
105 rg_prof_end("MAIN");
106 rg_prof_log("rg_log");
107 ?>
File tests/Makefile changed (mode: 100644) (index a225ac1..8d402f4)
1 1 tests := util db keys repo rights state user git prof bug log \ tests := util db keys repo rights state user git prof bug log \
2 hook_update hook_update_anon bug
2 hook_update hook_update_anon bug event
3 3 .PHONY: $(tests) .PHONY: $(tests)
4 4
5 5 all: $(tests) all: $(tests)
 
... ... bug:
37 37 log: log:
38 38 php log.php php log.php
39 39
40 event:
41 php event.php
42
40 43 hook_update: hook_update:
41 44 ./hook_update.sh ./hook_update.sh
42 45
File tests/email.php added (mode: 100644) (index 0000000..836fb25)
1 <?php
2 error_reporting(E_ALL | E_STRICT);
3 ini_set("track_errors", "On");
4
5 $INC = "../inc";
6 require_once($INC . "/init.inc.php");
7 require_once($INC . "/util.inc.php");
8
9 $rg_scripts = "../";
10 $rg_theme = "default";
11
12 rg_log_set_file("email.log");
13
14 $more = array(
15 "to" => "xxx@embedromix.ro"
16 );
17
18 $rg_admin_email = "admin@embedromix.ro";
19 $rg_admin_name = "Cătă";
20
21 $r = rg_mail("mail/user/key/new", $more);
22 print_r($r);
23 ?>
File tests/event.php added (mode: 100644) (index 0000000..d55cd6a)
1 <?php
2 error_reporting(E_ALL | E_STRICT);
3 ini_set("track_errors", "On");
4
5 // override the default
6 $rg_event_socket = "event.sock";
7
8 $INC = "../inc";
9 require_once($INC . "/init.inc.php");
10 require_once($INC . "/events.inc.php");
11 require_once($INC . "/sql.inc.php");
12 require_once($INC . "/struct.inc.php");
13
14 rg_log_set_file("event.log");
15
16 $rg_sql_debug = 1;
17
18 $db = rg_sql_open("dbname=trg");
19 if ($db === FALSE) {
20 rg_log("Cannot create a database (" . rg_sql_error() . ")!");
21 exit(1);
22 }
23
24 $r = rg_sql_struct_update($db, RG_DROP_TABLES|RG_IGNORE_ERRORS);
25 if ($r !== TRUE) {
26 rg_log("Cannot create struct (" . rg_sql_error() . ")!");
27 exit(1);
28 }
29
30 $sql = "TRUNCATE TABLE events";
31 $res = rg_sql_query($db, $sql);
32 if ($res === FALSE) {
33 echo "Cannot truncate table!\n";
34 exit(1);
35 }
36 rg_sql_free_result($res);
37
38 /*
39 * This function will generate an array of sub-events
40 */
41 function notif_new_repo($db, $ev)
42 {
43 rg_log("notif_new_repo: ev=" . rg_array2string($ev));
44
45 $ret = array();
46
47 // Send mail to the owner
48 $ret[] = array_merge($ev, "category" => 1);
49
50 // Send mail to admin
51 $ret[] = array_merge($ev, "category" => 2);
52
53 // Other junk
54 $ret[] = array_merge($ev, "category" => 3);
55
56 return $ret;
57 }
58
59 // Register an event function
60 $functions = array();
61 $functions[1] = "notif_new_repo";
62 $r = rg_event_register_functions($functions);
63 if ($r !== TRUE) {
64 echo "Cannot register functions!\n";
65 exit(1);
66 }
67
68 // defaults
69 $event = array(
70 "type" => 0,
71 "data" => array(
72 "category" => 1,
73 "repo_id" => 200
74 )
75 );
76
77 $r = rg_event_add($db, $event);
78 if ($r !== TRUE) {
79 echo "Cannot add event (" . rg_event_error() . ")!\n";
80 exit(1);
81 }
82
83 $r = rg_event_process_queue($db);
84 if ($r !== TRUE) {
85 echo "Cannot process queue (" . rg_event_error() . ")!\n";
86 exit(1);
87 }
88
89 rg_sql_close($db);
90
91 echo "event: OK!\n";
92 ?>
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/rocketgit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master