##// END OF EJS Templates
Implemented better support for Wildcard queries...
marcink -
r3063:ca2b2181 beta
parent child Browse files
Show More
This diff has been collapsed as it changes many lines, (2035 lines changed) Show them Hide them
@@ -0,0 +1,2035 b''
1 user_log_id,user_id,username,repository_id,repository_name,user_ip,action,action_date
2 40,11,bobbbb,7,Something,58.96.60.131,push:8ae497884817c13097315b1740f2dd4dc87146da,2012-06-20 06:24:58.397209
3 41,3,demo,8,Test_Repo,"",started_following_repo,2012-06-20 09:28:05.148974
4 42,3,demo,8,Test_Repo,"",user_created_repo,2012-06-20 09:28:05.16412
5 43,3,demo,8,Test_Repo,"",push_local:ef71a9202c55,2012-06-20 10:55:45.001052
6 44,3,demo,8,Test_Repo,"",push_local:38d49edbd7b2,2012-06-20 10:56:51.749613
7 45,3,demo,9,demo_repo,"",started_following_repo,2012-06-20 11:32:14.24928
8 46,3,demo,9,demo_repo,"",user_created_repo,2012-06-20 11:32:14.263506
9 47,3,demo,9,demo_repo,"",push_local:33ee55de14bc,2012-06-20 11:33:13.23204
10 48,3,demo,9,demo_repo,130.225.93.59,pull,2012-06-20 12:46:47.218691
11 49,3,demo,9,demo_repo,130.225.93.59,pull,2012-06-20 12:48:09.634995
12 50,3,demo,9,demo_repo,130.225.93.59,pull,2012-06-20 12:55:14.751441
13 51,3,demo,9,demo_repo,130.225.93.59,pull,2012-06-20 13:21:12.623288
14 56,3,demo,9,demo_repo,130.225.93.59,pull,2012-06-20 15:12:46.55823
15 57,3,demo,12,rawr,"",started_following_repo,2012-06-20 17:16:42.947936
16 58,3,demo,12,rawr,"",user_created_repo,2012-06-20 17:16:42.962133
17 59,3,demo,12,rawr,"",stopped_following_repo,2012-06-20 17:17:12.759495
18 60,3,demo,12,rawr,"",started_following_repo,2012-06-20 17:17:28.877751
19 62,3,demo,12,rawr,"",user_forked_repo:fork-rawr,2012-06-20 17:17:48.439005
20 64,3,demo,14,fork-demo_repo-cubed,"",started_following_repo,2012-06-20 18:54:02.751941
21 65,3,demo,9,demo_repo,"",user_forked_repo:fork-demo_repo-cubed,2012-06-20 18:54:02.767968
22 66,3,demo,14,fork-demo_repo-cubed,"",user_created_fork:fork-demo_repo-cubed,2012-06-20 18:54:02.777189
23 67,1,default,4,fork-fork-test,194.105.98.146,pull,2012-06-20 21:53:57.018888
24 68,1,default,7,Something,54.247.183.89,pull,2012-06-21 01:11:19.524998
25 69,3,demo,15,wibblewobble,"",started_following_repo,2012-06-21 10:21:31.937511
26 70,3,demo,15,wibblewobble,"",user_created_repo,2012-06-21 10:21:31.952874
27 71,3,demo,15,wibblewobble,"",push_local:c1953b3f4981,2012-06-21 10:23:05.881392
28 72,3,demo,8,Test_Repo,"",user_commented_revision:38d49edbd7b2599acf9ef40198d9107616c1faea,2012-06-21 21:11:46.159601
29 73,3,demo,8,Test_Repo,"",push_local:1b6b9ca4d1e2,2012-06-21 21:13:03.715136
30 74,3,demo,8,Test_Repo,"",user_commented_revision:1b6b9ca4d1e2776d8229f032c3a3136ae8c709a5,2012-06-21 21:13:32.771404
31 75,3,demo,8,Test_Repo,"",user_commented_revision:1b6b9ca4d1e2776d8229f032c3a3136ae8c709a5,2012-06-21 21:13:58.118806
32 76,1,default,4,fork-fork-test,98.215.125.44,pull,2012-06-22 09:04:39.8341
33 77,1,default,1,test,98.215.125.44,pull,2012-06-22 09:06:34.310867
34 78,3,demo,16,My-Demo-Test,"",started_following_repo,2012-06-22 09:24:25.528203
35 79,3,demo,16,My-Demo-Test,"",user_created_repo,2012-06-22 09:24:25.544844
36 80,3,demo,16,My-Demo-Test,"",push_local:c011a9245a0a,2012-06-22 09:25:51.981168
37 81,3,demo,17,fork-test1,"",started_following_repo,2012-06-22 12:45:00.782089
38 82,3,demo,7,Something,"",user_forked_repo:fork-test1,2012-06-22 12:45:00.874723
39 83,3,demo,17,fork-test1,"",user_created_fork:fork-test1,2012-06-22 12:45:00.888746
40 84,1,default,17,fork-test1,193.111.227.10,pull,2012-06-22 12:46:05.626038
41 85,3,demo,17,fork-test1,"",push_local:fbba7ec0a373,2012-06-22 12:47:02.869839
42 86,3,demo,,testuser,"",started_following_repo,2012-06-22 13:07:21.784074
43 87,3,demo,,testuser,"",user_created_repo,2012-06-22 13:07:21.797918
44 52,12,asddsaasd,,asdasd,"",started_following_repo,2012-06-20 13:29:33.432553
45 53,12,asddsaasd,,asdasd,"",user_created_repo,2012-06-20 13:29:33.443905
46 54,3,demo,,foo-bar,"",started_following_repo,2012-06-20 13:41:00.903917
47 55,3,demo,,foo-bar,"",user_created_repo,2012-06-20 13:41:00.919042
48 61,3,demo,,fork-rawr,"",started_following_repo,2012-06-20 17:17:48.419615
49 63,3,demo,,fork-rawr,"",user_created_fork:fork-rawr,2012-06-20 17:17:48.45108
50 88,3,demo,,testuser,"",user_deleted_repo,2012-06-22 13:08:17.608089
51 89,3,demo,8,Test_Repo,"",stopped_following_repo,2012-06-22 13:09:37.992254
52 90,3,demo,8,Test_Repo,"",started_following_repo,2012-06-22 13:09:39.613543
53 91,3,demo,8,Test_Repo,"",stopped_following_repo,2012-06-22 13:09:41.493402
54 92,3,demo,19,testmaster,"",started_following_repo,2012-06-22 13:10:21.695641
55 93,3,demo,19,testmaster,"",user_created_repo,2012-06-22 13:10:21.708814
56 96,3,demo,19,testmaster,"",push_local:b33786b10a28,2012-06-22 13:15:36.222686
57 104,3,demo,24,fork-Something,"",started_following_repo,2012-06-25 18:03:33.068935
58 105,3,demo,7,Something,"",user_forked_repo:fork-Something,2012-06-25 18:03:33.13689
59 106,3,demo,24,fork-Something,"",user_created_fork:fork-Something,2012-06-25 18:03:33.149499
60 107,3,demo,8,Test_Repo,"",user_commented_revision:1b6b9ca4d1e2776d8229f032c3a3136ae8c709a5,2012-06-25 18:04:15.229245
61 108,15,Vipous,25,My1,"",started_following_repo,2012-06-25 22:03:18.626137
62 109,15,Vipous,25,My1,"",user_created_repo,2012-06-25 22:03:18.64231
63 110,15,Vipous,25,My1,"",push_local:7de476a79614,2012-06-25 22:03:56.832111
64 111,3,demo,26,test12,"",started_following_repo,2012-06-26 04:49:54.757548
65 112,3,demo,26,test12,"",user_created_repo,2012-06-26 04:49:54.772195
66 113,1,default,26,test12,119.75.53.154,pull,2012-06-26 04:50:18.237028
67 114,3,demo,26,test12,119.75.53.154,push:50bafc0269a534dd41937214d0b35a43f65d8251,2012-06-26 04:51:04.26479
68 115,17,pribeiro,,sync,"",started_following_repo,2012-06-26 11:11:45.473209
69 116,17,pribeiro,,sync,"",user_created_repo,2012-06-26 11:11:45.487411
70 117,17,pribeiro,,sync,"",user_deleted_repo,2012-06-26 11:13:46.254567
71 118,18,admin_xanroot,28,new_repo,"",started_following_repo,2012-06-26 14:39:12.939952
72 119,18,admin_xanroot,28,new_repo,"",user_created_repo,2012-06-26 14:39:12.954647
73 120,2,admin,29,otro-test,"",started_following_repo,2012-06-26 19:44:05.282141
74 121,2,admin,29,otro-test,"",admin_created_repo,2012-06-26 19:44:05.29657
75 122,2,admin,29,otro-test,"",admin_updated_repo,2012-06-26 19:44:47.598164
76 123,1,default,29,otro-test,190.84.240.187,push:aeb60b7e53696fa8deaaf4881cf02cdbf4698bbc,2012-06-26 19:47:33.677685
77 124,22,sven-teichmann,30,Test,"",started_following_repo,2012-06-27 12:07:55.455967
78 125,22,sven-teichmann,30,Test,"",user_created_repo,2012-06-27 12:07:55.471798
79 126,3,demo,31,fork-new_repo,"",started_following_repo,2012-06-27 16:22:20.091073
80 127,3,demo,28,new_repo,"",user_forked_repo:fork-new_repo,2012-06-27 16:22:20.104674
81 128,3,demo,31,fork-new_repo,"",user_created_fork:fork-new_repo,2012-06-27 16:22:20.11418
82 129,3,demo,32,big-project,"",started_following_repo,2012-06-27 16:37:55.369402
83 130,3,demo,32,big-project,"",user_created_repo,2012-06-27 16:37:55.383717
84 131,3,demo,32,big-project,195.238.92.121,push:5645e36ef4c9dbdd31709f1d234df008a8a8ce8c,2012-06-27 16:39:07.148939
85 132,3,demo,32,big-project,195.238.92.121,push:06d5302c4830e5af52f06c462f11f75107b2a1ff,2012-06-27 16:39:45.482592
86 133,3,demo,32,big-project,"",user_commented_revision:06d5302c4830e5af52f06c462f11f75107b2a1ff,2012-06-27 16:42:21.533609
87 134,3,demo,32,big-project,"",user_commented_revision:06d5302c4830e5af52f06c462f11f75107b2a1ff,2012-06-27 16:42:48.278721
88 135,3,demo,32,big-project,"",stopped_following_repo,2012-06-27 16:46:16.105454
89 136,3,demo,32,big-project,"",started_following_repo,2012-06-27 16:46:17.496644
90 137,3,demo,32,big-project,"",stopped_following_repo,2012-06-27 16:46:19.299402
91 138,3,demo,32,big-project,"",started_following_repo,2012-06-27 16:46:20.235067
92 139,3,demo,32,big-project,"",user_commented_pull_request:3,2012-06-27 17:25:45.106764
93 140,3,demo,33,fork-big-project,"",started_following_repo,2012-06-27 17:30:03.65222
94 141,3,demo,32,big-project,"",user_forked_repo:fork-big-project,2012-06-27 17:30:03.666404
95 142,3,demo,33,fork-big-project,"",user_created_fork:fork-big-project,2012-06-27 17:30:03.676956
96 143,3,demo,34,a,"",started_following_repo,2012-06-27 17:38:09.019648
97 144,3,demo,34,a,"",user_created_repo,2012-06-27 17:38:09.0339
98 145,3,demo,35,fork-Something22,"",started_following_repo,2012-06-28 11:00:39.678572
99 146,3,demo,7,Something,"",user_forked_repo:fork-Something22,2012-06-28 11:00:39.737584
100 147,3,demo,35,fork-Something22,"",user_created_fork:fork-Something22,2012-06-28 11:00:39.754509
101 148,3,demo,36,bootstrap,"",started_following_repo,2012-06-29 08:21:06.920203
102 149,3,demo,36,bootstrap,"",user_created_repo,2012-06-29 08:21:06.932926
103 150,18,admin_xanroot,28,new_repo,"",stopped_following_repo,2012-06-29 13:24:05.476554
104 151,18,admin_xanroot,28,new_repo,"",started_following_repo,2012-06-29 13:24:07.796049
105 152,18,admin_xanroot,37,ааввя,"",started_following_repo,2012-06-29 14:29:18.52356
106 153,18,admin_xanroot,37,ааввя,"",user_created_repo,2012-06-29 14:29:18.536725
107 154,2,admin,38,code-review-test,"",started_following_repo,2012-06-29 14:51:32.715801
108 155,2,admin,38,code-review-test,"",admin_created_repo,2012-06-29 14:51:32.730258
109 156,2,admin,1,test,"",user_commented_pull_request:1,2012-06-29 14:54:59.436222
110 157,2,admin,1,test,"",user_commented_pull_request:1,2012-06-29 14:55:14.228553
111 158,2,admin,1,test,"",user_commented_pull_request:1,2012-06-29 14:55:22.443143
112 159,2,admin,1,test,"",user_commented_pull_request:1,2012-06-29 14:55:37.609157
113 160,2,admin,3,fork-test,"",user_commented_revision:8af86cb62c34b04cf2b1e3c9fcd2aa19e2e79caa,2012-06-29 14:56:01.991353
114 161,1,default,38,code-review-test,62.116.219.97,pull,2012-06-29 14:57:31.272853
115 162,2,admin,39,fork-code-review-test,"",started_following_repo,2012-06-29 15:03:28.825569
116 163,2,admin,38,code-review-test,"",user_forked_repo:fork-code-review-test,2012-06-29 15:03:28.875867
117 164,2,admin,39,fork-code-review-test,"",user_created_fork:fork-code-review-test,2012-06-29 15:03:28.883669
118 165,2,admin,39,fork-code-review-test,62.116.219.97,push:ac19ef61aab0b008acb5dac5d53457cbd278d927,2012-06-29 15:03:44.690869
119 166,2,admin,38,code-review-test,"",user_commented_pull_request:5,2012-06-29 15:07:50.753441
120 167,2,admin,39,fork-code-review-test,"",user_commented_revision:ac19ef61aab0b008acb5dac5d53457cbd278d927,2012-06-29 15:08:06.700958
121 168,2,admin,38,code-review-test,"",user_commented_pull_request:5,2012-06-29 15:08:20.290949
122 169,2,admin,38,code-review-test,"",user_commented_pull_request:5,2012-06-29 15:08:43.746906
123 170,3,demo,40,group/fork-a,"",started_following_repo,2012-07-01 18:28:49.022357
124 171,3,demo,34,a,"",user_forked_repo:group/fork-a,2012-07-01 18:28:49.039621
125 172,3,demo,40,group/fork-a,"",user_created_fork:group/fork-a,2012-07-01 18:28:49.050748
126 173,3,demo,16,My-Demo-Test,"",push_local:5ac30fe040bd,2012-07-02 17:29:26.91197
127 174,1,default,36,bootstrap,78.53.1.77,pull,2012-07-02 19:33:15.148459
128 175,2,admin,,asdasd,"",admin_deleted_repo,2012-07-03 00:54:27.51389
129 94,3,demo,,testclone,"",started_following_repo,2012-06-22 13:10:54.479092
130 101,14,rune,,fork-rune-test,"",started_following_repo,2012-06-25 15:06:20.402391
131 97,3,demo,,dummy,"",started_following_repo,2012-06-25 00:12:56.20161
132 98,3,demo,,dummy,"",user_created_repo,2012-06-25 00:12:56.210618
133 99,14,rune,,rune-test,"",started_following_repo,2012-06-25 15:05:18.894561
134 100,14,rune,,rune-test,"",user_created_repo,2012-06-25 15:05:18.908953
135 102,14,rune,,rune-test,"",user_forked_repo:fork-rune-test,2012-06-25 15:06:20.418213
136 237,1,default,36,bootstrap,92.229.108.18,pull,2012-07-11 23:16:28.235183
137 95,3,demo,,testclone,"",user_created_repo,2012-06-22 13:10:54.492868
138 177,2,admin,,testclone,"",admin_deleted_repo,2012-07-03 00:54:44.781032
139 103,14,rune,,fork-rune-test,"",user_created_fork:fork-rune-test,2012-06-25 15:06:20.429444
140 178,2,admin,,fork-rune-test,"",admin_deleted_repo,2012-07-03 00:54:53.395495
141 179,2,admin,,dummy,"",admin_deleted_repo,2012-07-03 00:54:56.740108
142 180,2,admin,,foo-bar,"",admin_deleted_repo,2012-07-03 00:54:59.755216
143 238,40,cowwoc,54,glib,"",started_following_repo,2012-07-12 00:09:07.867216
144 182,15,Vipous,25,My1,"",push_local:96546c4c668d,2012-07-03 22:52:15.186673
145 183,15,Vipous,25,My1,"",push_local:f650cc084095,2012-07-03 22:53:20.761064
146 184,15,Vipous,25,My1,"",push_local:e55af939aaf5,2012-07-03 22:54:18.480735
147 185,28,razpdx,38,code-review-test,"",user_commented_revision:d5422faf648cc589425cd3b0dbf1f6dbf93036a0,2012-07-04 08:10:08.771284
148 186,28,razpdx,41,fork-code-review-test1111111,"",started_following_repo,2012-07-04 08:11:23.633652
149 187,28,razpdx,38,code-review-test,"",user_forked_repo:fork-code-review-test1111111,2012-07-04 08:11:25.10245
150 188,28,razpdx,41,fork-code-review-test1111111,"",user_created_fork:fork-code-review-test1111111,2012-07-04 08:11:25.110291
151 189,3,demo,43,bar,"",started_following_repo,2012-07-05 14:37:38.394712
152 190,3,demo,43,bar,"",user_created_repo,2012-07-05 14:37:38.404527
153 191,3,demo,42,foo,"",started_following_repo,2012-07-05 14:38:19.351357
154 192,3,demo,42,foo,"",user_created_repo,2012-07-05 14:38:19.367056
155 193,3,demo,9,demo_repo,"",push_local:14fcc9365f2a,2012-07-05 22:53:20.216762
156 194,31,jtiai,44,diff-test,"",started_following_repo,2012-07-06 11:23:24.475194
157 195,31,jtiai,44,diff-test,"",user_created_repo,2012-07-06 11:23:24.491639
158 196,31,jtiai,44,diff-test,62.240.70.253,push:bca174fa48db2eb05db5bd4532191dac269e97b2,2012-07-06 11:25:02.929509
159 197,31,jtiai,44,diff-test,62.240.70.253,push:50daf150549b8d48676889dcb713f1f4e0e4bc9d,2012-07-06 11:26:14.260627
160 198,2,admin,44,diff-test,"",admin_updated_repo,2012-07-06 19:57:44.363539
161 199,2,admin,44,diff-test,"",admin_updated_repo,2012-07-06 19:57:48.132041
162 200,1,default,44,diff-test,78.53.7.202,pull,2012-07-06 19:58:55.97104
163 201,32,shabutora,45,group/fork-bootstrap,"",started_following_repo,2012-07-07 07:28:38.272328
164 202,32,shabutora,36,bootstrap,"",user_forked_repo:group/fork-bootstrap,2012-07-07 07:28:39.509986
165 203,32,shabutora,45,group/fork-bootstrap,"",user_created_fork:group/fork-bootstrap,2012-07-07 07:28:39.523403
166 206,3,demo,,GitRepoTest,"",started_following_repo,2012-07-09 15:19:28.134838
167 207,3,demo,,GitRepoTest,"",user_created_repo,2012-07-09 15:19:28.145858
168 208,3,demo,,GitRepoTest,"",push_local:5caba17c3e28,2012-07-09 15:19:59.181736
169 209,3,demo,,GitRepoTest,"",user_deleted_repo,2012-07-09 15:22:02.989814
170 210,3,demo,32,big-project,"",user_commented_revision:06d5302c4830e5af52f06c462f11f75107b2a1ff,2012-07-09 21:43:51.82571
171 211,3,demo,32,big-project,"",user_commented_revision:06d5302c4830e5af52f06c462f11f75107b2a1ff,2012-07-09 21:43:59.440606
172 212,3,demo,32,big-project,"",user_commented_revision:06d5302c4830e5af52f06c462f11f75107b2a1ff,2012-07-09 21:44:06.259449
173 213,3,demo,15,wibblewobble,"",user_commented_revision:c1953b3f4981e57d0031f4307f70209706f204f3,2012-07-09 21:45:16.908265
174 214,3,demo,15,wibblewobble,"",user_commented_revision:c1953b3f4981e57d0031f4307f70209706f204f3,2012-07-09 21:45:29.881903
175 217,2,admin,,rm__20120709_152203_19234__GitRepoTest,"",started_following_repo,2012-07-11 01:23:59.921383
176 218,2,admin,,rm__20120709_152203_19234__GitRepoTest,"",admin_deleted_repo,2012-07-11 01:25:33.983055
177 221,38,zenqw,51,fork-test-12345,"",started_following_repo,2012-07-11 13:05:17.345386
178 222,38,zenqw,1,test,"",user_forked_repo:fork-test-12345,2012-07-11 13:05:17.362995
179 223,38,zenqw,51,fork-test-12345,"",user_created_fork:fork-test-12345,2012-07-11 13:05:17.370362
180 224,38,zenqw,51,fork-test-12345,217.153.157.250,pull,2012-07-11 13:05:51.790618
181 225,38,zenqw,51,fork-test-12345,217.153.157.250,"push:ebf2e5c36ee3008d6fde8376e0dc2859c764aeef,6854386e16136812b9219e9d5e2971c87419eafa,46371e1dff2357d51e581e55882415bd18a5db8c",2012-07-11 13:07:46.354331
182 226,38,zenqw,51,fork-test-12345,217.153.157.250,push:4db220a6e8a720ffd78d1fc383e3361e9f85e930,2012-07-11 13:10:13.793368
183 227,38,zenqw,1,test,"",user_commented_pull_request:6,2012-07-11 13:11:54.473213
184 228,38,zenqw,1,test,"",user_commented_pull_request:6,2012-07-11 13:12:03.64804
185 229,38,zenqw,52,fork-fork-test-12345_2,"",started_following_repo,2012-07-11 13:14:31.237173
186 230,38,zenqw,51,fork-test-12345,"",user_forked_repo:fork-fork-test-12345_2,2012-07-11 13:14:31.2571
187 231,38,zenqw,52,fork-fork-test-12345_2,"",user_created_fork:fork-fork-test-12345_2,2012-07-11 13:14:31.268722
188 232,38,zenqw,52,fork-fork-test-12345_2,217.153.157.250,pull,2012-07-11 13:15:52.326756
189 233,38,zenqw,52,fork-fork-test-12345_2,217.153.157.250,"push:b9567e91f6ee7cd18b6332608a5a0ed12256ea48,2f709872121b0875b02f4fbfafa8fccd4c0613db",2012-07-11 13:16:51.063259
190 234,38,zenqw,51,fork-test-12345,"",user_commented_pull_request:7,2012-07-11 13:18:04.300327
191 239,40,cowwoc,54,glib,"",user_created_repo,2012-07-12 00:09:07.883466
192 240,3,demo,38,code-review-test,"",user_commented_pull_request:8,2012-07-12 00:50:50.791122
193 241,3,demo,38,code-review-test,"",user_commented_pull_request:8,2012-07-12 00:51:04.795167
194 242,3,demo,38,code-review-test,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-07-12 13:41:59.717658
195 243,43,lpyedge,55,group/brhg,"",started_following_repo,2012-07-12 15:09:28.550696
196 244,43,lpyedge,55,group/brhg,"",user_created_repo,2012-07-12 15:09:28.562524
197 245,43,lpyedge,56,brgit,"",started_following_repo,2012-07-12 15:18:17.687605
198 246,43,lpyedge,56,brgit,"",user_created_repo,2012-07-12 15:18:17.702136
199 247,1,default,34,a,54.247.183.89,pull,2012-07-12 16:53:15.165512
200 248,45,krhodecode,1,test,"",user_commented_revision:ef02269209cd431c0cd0ee929ba37ae895651d69,2012-07-12 23:09:25.38717
201 249,45,krhodecode,42,foo,"",user_commented_revision:ca953e8c5c1ada44e9a8f945a0a6999d2f44310d,2012-07-12 23:14:07.819338
202 250,45,krhodecode,57,SuperProject,"",started_following_repo,2012-07-12 23:17:38.213634
203 251,45,krhodecode,57,SuperProject,"",user_created_repo,2012-07-12 23:17:38.229359
204 252,45,krhodecode,57,SuperProject,216.51.137.66,push:a3188ce9ed64822ceae497665910c2e18cddf021,2012-07-12 23:23:23.111788
205 253,3,demo,38,code-review-test,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-07-13 14:22:00.003158
206 254,46,snazy2000,58,group/Test,"",started_following_repo,2012-07-13 19:14:31.959033
207 255,46,snazy2000,58,group/Test,"",user_created_repo,2012-07-13 19:14:31.972509
208 256,2,admin,1,test,"",user_commented_revision:ef02269209cd431c0cd0ee929ba37ae895651d69,2012-07-15 03:03:17.100702
209 204,34,qqqqq,,zaraza,"",started_following_repo,2012-07-08 01:43:26.053084
210 205,34,qqqqq,,zaraza,"",user_created_repo,2012-07-08 01:43:26.067756
211 215,35,kvaster,,asd,"",started_following_repo,2012-07-09 22:03:29.676651
212 216,35,kvaster,,asd,"",user_created_repo,2012-07-09 22:03:29.688872
213 219,37,tester,,test2,"",started_following_repo,2012-07-11 11:07:19.065559
214 220,37,tester,,test2,"",user_created_repo,2012-07-11 11:07:19.080323
215 257,2,admin,38,code-review-test,"",user_commented_pull_request:8,2012-07-15 03:21:36.545532
216 258,2,admin,38,code-review-test,"",user_closed_pull_request:8,2012-07-15 03:21:36.556543
217 259,3,demo,59,fasdf,"",started_following_repo,2012-07-15 12:27:25.654257
218 260,3,demo,59,fasdf,"",user_created_repo,2012-07-15 12:27:25.670633
219 261,3,demo,60,group/aaa1,"",started_following_repo,2012-07-15 12:27:42.824398
220 262,3,demo,60,group/aaa1,"",user_created_repo,2012-07-15 12:27:42.834237
221 263,3,demo,34,a,"",user_updated_repo,2012-07-15 13:47:35.934007
222 264,3,demo,61,group/testowe-repo,"",started_following_repo,2012-07-15 13:54:10.774348
223 265,3,demo,61,group/testowe-repo,"",user_created_repo,2012-07-15 13:54:10.784709
224 266,3,demo,61,group/testowe-repo,109.173.164.98,pull,2012-07-15 13:55:19.296932
225 267,3,demo,61,group/testowe-repo,"",user_updated_repo,2012-07-15 13:57:16.969058
226 235,2,admin,,rm__20120711_012534_20311__rm__20120709_152203_19234__GitRepoTest,"",started_following_repo,2012-07-11 22:50:22.745467
227 268,47,testuser,62,My-demo,"",started_following_repo,2012-07-15 20:00:47.633404
228 269,47,testuser,62,My-demo,"",user_created_repo,2012-07-15 20:00:47.64378
229 270,48,volcan,63,test9,"",started_following_repo,2012-07-15 20:45:08.177239
230 271,48,volcan,63,test9,"",user_created_repo,2012-07-15 20:45:08.191869
231 272,48,volcan,63,test9,"",push_local:7e10d450821a,2012-07-15 20:46:42.370199
232 273,48,volcan,63,test9,"",push_local:049788cfb4b5,2012-07-15 20:48:26.176589
233 274,48,volcan,63,test9,"",user_commented_revision:049788cfb4b5254813312395aa380e988c32bbfb,2012-07-15 20:48:42.031217
234 275,48,volcan,64,fork-test9,"",started_following_repo,2012-07-15 20:51:55.738241
235 276,48,volcan,63,test9,"",user_forked_repo:fork-test9,2012-07-15 20:51:55.749793
236 277,48,volcan,64,fork-test9,"",user_created_fork:fork-test9,2012-07-15 20:51:55.757696
237 278,3,demo,65,COMMON,"",started_following_repo,2012-07-16 14:38:36.330869
238 279,3,demo,65,COMMON,"",user_created_repo,2012-07-16 14:38:36.341796
239 280,3,demo,39,fork-code-review-test,"",user_commented_revision:30853f4bde2f2b6f0a7126392b9b1b4c5ea37e0a,2012-07-17 09:26:23.907503
240 281,3,demo,39,fork-code-review-test,"",user_commented_revision:30853f4bde2f2b6f0a7126392b9b1b4c5ea37e0a,2012-07-17 09:26:58.039752
241 282,3,demo,39,fork-code-review-test,"",user_commented_revision:c5ed575f313788acd04614e3e0c13a5cdf5d7b39,2012-07-17 09:29:02.389958
242 283,3,demo,39,fork-code-review-test,"",user_commented_revision:c5ed575f313788acd04614e3e0c13a5cdf5d7b39,2012-07-17 09:29:39.287759
243 284,3,demo,38,code-review-test,"",user_commented_revision:0e4171fdb9d4267aa1145b840529d75673ea553d,2012-07-17 11:56:13.655476
244 285,3,demo,38,code-review-test,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-07-17 11:57:32.735913
245 286,52,prefer,39,fork-code-review-test,"",user_commented_revision:ac19ef61aab0b008acb5dac5d53457cbd278d927,2012-07-17 12:22:56.170784
246 287,52,prefer,38,code-review-test,"",user_commented_revision:30853f4bde2f2b6f0a7126392b9b1b4c5ea37e0a,2012-07-17 12:25:01.172222
247 288,2,admin,34,a,"",push_local:445b722bf31d,2012-07-17 16:49:47.04337
248 289,3,demo,66,pm-test,"",started_following_repo,2012-07-17 17:04:59.403792
249 290,3,demo,8,Test_Repo,"",user_forked_repo:pm-test,2012-07-17 17:04:59.421648
250 291,3,demo,66,pm-test,"",user_created_fork:pm-test,2012-07-17 17:04:59.432594
251 292,3,demo,66,pm-test,"",push_local:6cac4edb9e76,2012-07-17 17:06:10.733221
252 293,3,demo,66,pm-test,"",push_local:ceabeecd9ee8,2012-07-17 17:08:49.922859
253 294,3,demo,67,group/aaa-repo,"",started_following_repo,2012-07-17 17:22:47.868349
254 295,3,demo,67,group/aaa-repo,"",user_created_repo,2012-07-17 17:22:47.883704
255 296,3,demo,68,aaa-project,"",started_following_repo,2012-07-17 17:23:40.541656
256 297,3,demo,68,aaa-project,"",user_created_repo,2012-07-17 17:23:40.552371
257 298,54,dude,69,group/bootstrap-fork,"",started_following_repo,2012-07-17 18:43:10.035674
258 299,54,dude,36,bootstrap,"",user_forked_repo:group/bootstrap-fork,2012-07-17 18:43:11.233142
259 300,54,dude,69,group/bootstrap-fork,"",user_created_fork:group/bootstrap-fork,2012-07-17 18:43:11.241307
260 301,54,dude,69,group/bootstrap-fork,"",user_commented_revision:550e375af08a5b6ad401c043f8c0d2f3b1d3b6c2,2012-07-17 18:46:04.298716
261 302,54,dude,70,group/A-new-git-repo,"",started_following_repo,2012-07-17 18:47:57.52576
262 303,54,dude,70,group/A-new-git-repo,"",user_created_repo,2012-07-17 18:47:57.537413
263 304,2,admin,71,rkquery-fork,"",started_following_repo,2012-07-18 15:54:45.756295
264 305,2,admin,71,rkquery-fork,"",admin_created_repo,2012-07-18 15:54:45.774453
265 306,61,test2,36,bootstrap,"",user_commented_revision:cd2d82150cc27c1f81d2394a22efbf2dbec0e7be,2012-07-20 06:02:57.703606
266 307,52,prefer,36,bootstrap,"",user_commented_revision:cd2d82150cc27c1f81d2394a22efbf2dbec0e7be,2012-07-20 08:38:49.709445
267 308,52,prefer,36,bootstrap,"",user_commented_revision:cd2d82150cc27c1f81d2394a22efbf2dbec0e7be,2012-07-20 08:50:24.082494
268 309,64,selecta,72,testgit,"",started_following_repo,2012-07-20 10:46:02.535088
269 310,64,selecta,72,testgit,"",user_created_repo,2012-07-20 10:46:02.548252
270 311,64,selecta,72,testgit,"",push_local:62a88b300d22,2012-07-20 10:46:16.81029
271 312,63,derTester,73,derTester-testrepo,"",started_following_repo,2012-07-20 10:54:39.064697
272 313,63,derTester,73,derTester-testrepo,"",user_created_repo,2012-07-20 10:54:39.079807
273 314,63,derTester,73,derTester-testrepo,"unknown, 194.8.219.19",push:84b31af757fe28ea9b9ac66053509a3a52b24f5c,2012-07-20 10:57:31.114727
274 315,63,derTester,73,derTester-testrepo,"",user_commented_revision:84b31af757fe28ea9b9ac66053509a3a52b24f5c,2012-07-20 11:07:50.716058
275 316,63,derTester,73,derTester-testrepo,"",user_commented_revision:84b31af757fe28ea9b9ac66053509a3a52b24f5c,2012-07-20 11:08:03.688221
276 317,63,derTester,73,derTester-testrepo,"",user_commented_revision:84b31af757fe28ea9b9ac66053509a3a52b24f5c,2012-07-20 11:08:16.565505
277 318,63,derTester,73,derTester-testrepo,"unknown, 194.8.219.19",push:5281b955815c98305051d3c008ff69c4ed533c0d,2012-07-20 11:11:10.31612
278 319,63,derTester,74,fork-derTester-testrepo,"",started_following_repo,2012-07-20 11:25:25.419964
279 320,63,derTester,73,derTester-testrepo,"",user_forked_repo:fork-derTester-testrepo,2012-07-20 11:25:25.438168
280 321,63,derTester,74,fork-derTester-testrepo,"",user_created_fork:fork-derTester-testrepo,2012-07-20 11:25:25.447682
281 322,63,derTester,74,fork-derTester-testrepo,"unknown, 194.8.219.19",pull,2012-07-20 11:26:37.491958
282 323,63,derTester,74,fork-derTester-testrepo,"unknown, 194.8.219.19",push:f2735aac6abe27c8f01e76faf5c283bf46c4401f,2012-07-20 11:27:44.331062
283 324,63,derTester,73,derTester-testrepo,"",user_commented_pull_request:9,2012-07-20 11:29:31.042888
284 325,63,derTester,73,derTester-testrepo,"",user_closed_pull_request:9,2012-07-20 11:29:31.049204
285 326,66,frankschepers,75,group/TestRepFs,"",started_following_repo,2012-07-20 11:30:19.886707
286 327,66,frankschepers,75,group/TestRepFs,"",user_created_repo,2012-07-20 11:30:19.898463
287 328,66,frankschepers,76,group/testrep2,"",started_following_repo,2012-07-20 11:31:20.300601
288 329,66,frankschepers,76,group/testrep2,"",user_created_repo,2012-07-20 11:31:20.311022
289 330,66,frankschepers,75,group/TestRepFs,"",push_local:17387d4e13a1,2012-07-20 11:33:31.893613
290 331,66,frankschepers,75,group/TestRepFs,"",push_local:a897a2d13bc2,2012-07-20 11:34:22.754229
291 332,63,derTester,73,derTester-testrepo,"unknown, 194.8.219.19",push:1214054a771a04bc69963bf26dfbc8ee2cb9122b,2012-07-20 11:36:39.441367
292 333,63,derTester,74,fork-derTester-testrepo,"unknown, 194.8.219.19",pull,2012-07-20 11:36:51.746969
293 334,63,derTester,73,derTester-testrepo,"unknown, 194.8.219.19","push:f2735aac6abe27c8f01e76faf5c283bf46c4401f,0659071d48979ed22941a269c97368b4663ae958",2012-07-20 11:37:40.944129
294 335,66,frankschepers,75,group/TestRepFs,137.120.73.17,pull,2012-07-20 11:39:49.54307
295 336,1,default,24,fork-Something,64.208.49.214,pull,2012-07-20 13:49:55.94902
296 337,1,default,24,fork-Something,64.208.49.218,pull,2012-07-20 13:54:22.988482
297 338,3,demo,68,aaa-project,"",user_updated_repo,2012-07-20 15:39:52.858365
298 339,63,derTester,73,derTester-testrepo,"",user_updated_repo,2012-07-20 16:27:14.407843
299 340,67,openinformation,73,derTester-testrepo,"",push_local:328fae54d511,2012-07-20 16:31:46.146409
300 341,67,openinformation,73,derTester-testrepo,"",push_local:0c569a05f314,2012-07-20 16:32:54.826366
301 342,63,derTester,73,derTester-testrepo,"",user_commented_revision:328fae54d511ba83c8e9ffe1cb9f42d30904a4a8,2012-07-20 16:33:01.509041
302 343,63,derTester,73,derTester-testrepo,"",user_commented_revision:328fae54d511ba83c8e9ffe1cb9f42d30904a4a8,2012-07-20 16:33:18.910418
303 344,67,openinformation,73,derTester-testrepo,"",user_commented_revision:0c569a05f31488c3a0b0bef9540e774199d5761b,2012-07-20 16:33:47.140002
304 345,63,derTester,73,derTester-testrepo,"",user_commented_revision:0c569a05f31488c3a0b0bef9540e774199d5761b,2012-07-20 16:35:08.640552
305 346,67,openinformation,73,derTester-testrepo,"",user_commented_revision:0c569a05f31488c3a0b0bef9540e774199d5761b,2012-07-20 16:35:10.546976
306 347,63,derTester,73,derTester-testrepo,"",user_commented_revision:0c569a05f31488c3a0b0bef9540e774199d5761b,2012-07-20 16:35:19.485402
307 348,63,derTester,73,derTester-testrepo,"",user_commented_revision:0c569a05f31488c3a0b0bef9540e774199d5761b,2012-07-20 16:35:47.956513
308 349,67,openinformation,73,derTester-testrepo,"",user_commented_revision:0c569a05f31488c3a0b0bef9540e774199d5761b,2012-07-20 16:36:19.043512
309 350,67,openinformation,73,derTester-testrepo,"",user_commented_revision:0c569a05f31488c3a0b0bef9540e774199d5761b,2012-07-20 16:36:48.577132
310 351,67,openinformation,73,derTester-testrepo,"",user_commented_revision:0c569a05f31488c3a0b0bef9540e774199d5761b,2012-07-20 16:38:16.822535
311 352,63,derTester,73,derTester-testrepo,"",user_commented_revision:0c569a05f31488c3a0b0bef9540e774199d5761b,2012-07-20 16:38:46.389457
312 353,3,demo,66,pm-test,"",user_commented_revision:1b6b9ca4d1e2776d8229f032c3a3136ae8c709a5,2012-07-20 18:48:42.618318
313 354,3,demo,71,rkquery-fork,"",user_commented_revision:06684d34a0dfeec4ca84eb3a4de3ac4eca659b5a,2012-07-20 18:53:30.111799
314 355,2,admin,66,pm-test,"",user_commented_revision:1b6b9ca4d1e2776d8229f032c3a3136ae8c709a5,2012-07-20 20:37:34.763255
315 356,2,admin,66,pm-test,"",user_commented_revision:1b6b9ca4d1e2776d8229f032c3a3136ae8c709a5,2012-07-20 20:37:54.48707
316 357,3,demo,77,group/testme-out,"",started_following_repo,2012-07-21 03:36:40.318489
317 358,3,demo,77,group/testme-out,"",user_created_repo,2012-07-21 03:36:40.33199
318 362,68,adam_cubiware,79,fork-testgit,"",started_following_repo,2012-07-21 12:42:44.576306
319 363,68,adam_cubiware,72,testgit,"",user_forked_repo:fork-testgit,2012-07-21 12:42:44.638332
320 364,68,adam_cubiware,79,fork-testgit,"",user_created_fork:fork-testgit,2012-07-21 12:42:44.652192
321 365,68,adam_cubiware,79,fork-testgit,"",push_local:ae0315d73341,2012-07-21 12:44:33.911138
322 366,68,adam_cubiware,79,fork-testgit,"",user_updated_repo,2012-07-21 12:47:12.163568
323 367,68,adam_cubiware,79,fork-testgit,"",push_local:db50409cdc5f,2012-07-21 12:53:44.632803
324 368,1,default,39,fork-code-review-test,91.143.250.55,pull,2012-07-21 23:48:23.449665
325 369,1,default,39,fork-code-review-test,91.143.250.55,pull,2012-07-21 23:48:36.982768
326 372,72,rushman,38,code-review-test,"",user_commented_pull_request:10,2012-07-22 23:44:39.072741
327 373,72,rushman,38,code-review-test,"",user_closed_pull_request:10,2012-07-22 23:44:39.082942
328 374,3,demo,34,a,"",user_updated_repo,2012-07-23 05:19:06.777651
329 375,2,admin,34,a,"",push_local:5478c7d290bc0a14d9cefd79ed5722a87f3815d5,2012-07-23 14:57:35.353962
330 376,2,admin,34,a,"",push_local:7ec6b566916b553f8ab92aaf1c993269b96b52ee,2012-07-23 14:57:47.489325
331 377,2,admin,34,a,"",push_local:7672806f881f67eb1441d00b16e983e761127cb6,2012-07-23 14:58:18.73749
332 378,2,admin,34,a,"",push_local:7f8b4f94e2a83394aa687e0bb110870769e9ca0a,2012-07-23 14:58:29.908109
333 379,75,treshnikov,44,diff-test,"",user_commented_revision:50daf150549b8d48676889dcb713f1f4e0e4bc9d,2012-07-23 16:43:41.7336
334 380,75,treshnikov,44,diff-test,"",user_commented_revision:50daf150549b8d48676889dcb713f1f4e0e4bc9d,2012-07-23 16:43:55.306834
335 381,3,demo,81,FS_dummy,"",started_following_repo,2012-07-24 11:59:32.839397
336 382,3,demo,81,FS_dummy,"",user_created_repo,2012-07-24 11:59:32.855419
337 383,67,openinformation,73,derTester-testrepo,"",user_commented_revision:0c569a05f31488c3a0b0bef9540e774199d5761b,2012-07-24 13:14:36.794825
338 384,67,openinformation,82,fork-derTester-testrepo2,"",started_following_repo,2012-07-24 13:21:01.528796
339 385,67,openinformation,73,derTester-testrepo,"",user_forked_repo:fork-derTester-testrepo2,2012-07-24 13:21:01.555045
340 386,67,openinformation,82,fork-derTester-testrepo2,"",user_created_fork:fork-derTester-testrepo2,2012-07-24 13:21:01.563889
341 387,77,test,34,a,"",user_commented_revision:5478c7d290bc0a14d9cefd79ed5722a87f3815d5,2012-07-24 15:38:45.147594
342 388,77,test,34,a,"",user_commented_revision:5478c7d290bc0a14d9cefd79ed5722a87f3815d5,2012-07-24 15:40:33.021633
343 389,77,test,34,a,"",user_commented_revision:5478c7d290bc0a14d9cefd79ed5722a87f3815d5,2012-07-24 15:40:53.491125
344 390,3,demo,83,group/roman-test,"",started_following_repo,2012-07-24 16:09:25.411937
345 391,3,demo,83,group/roman-test,"",user_created_repo,2012-07-24 16:09:25.426938
346 392,68,adam_cubiware,79,fork-testgit,"",push_local:d5c6ffefdf5499201c2679717d65d5a642f1e163,2012-07-24 19:33:06.111179
347 393,68,adam_cubiware,79,fork-testgit,"",user_commented_revision:d5c6ffefdf5499201c2679717d65d5a642f1e163,2012-07-24 19:33:44.899645
348 394,68,adam_cubiware,79,fork-testgit,"",user_updated_repo,2012-07-24 19:35:04.803706
349 395,68,adam_cubiware,79,group/fork-testgit,"",user_updated_repo,2012-07-24 19:37:19.243784
350 396,68,adam_cubiware,84,group/fork-Test_Repo,"",started_following_repo,2012-07-24 19:40:08.15438
351 397,68,adam_cubiware,8,Test_Repo,"",user_forked_repo:group/fork-Test_Repo,2012-07-24 19:40:08.173841
352 398,68,adam_cubiware,84,group/fork-Test_Repo,"",user_created_fork:group/fork-Test_Repo,2012-07-24 19:40:08.182255
353 399,68,adam_cubiware,84,group/fork-Test_Repo,"",user_commented_revision:1b6b9ca4d1e2776d8229f032c3a3136ae8c709a5,2012-07-24 19:41:34.833349
354 400,68,adam_cubiware,84,group/fork-Test_Repo,"",push_local:27213189ef4e7e8b47209d4e123042419cb1154a,2012-07-24 19:44:35.829394
355 401,68,adam_cubiware,8,Test_Repo,"",user_commented_pull_request:11,2012-07-24 19:47:49.707363
356 402,68,adam_cubiware,8,Test_Repo,"",user_commented_pull_request:11,2012-07-24 19:48:18.79552
357 403,68,adam_cubiware,8,Test_Repo,"",user_closed_pull_request:11,2012-07-24 19:48:18.804561
358 404,68,adam_cubiware,8,Test_Repo,"",user_commented_pull_request:12,2012-07-24 19:50:08.792408
359 405,68,adam_cubiware,8,Test_Repo,"",user_commented_pull_request:12,2012-07-24 19:50:21.615437
360 406,68,adam_cubiware,85,group/qbtest,"",started_following_repo,2012-07-24 19:54:48.682241
361 407,68,adam_cubiware,85,group/qbtest,"",user_created_repo,2012-07-24 19:54:48.693521
362 408,68,adam_cubiware,86,qbtest,"",started_following_repo,2012-07-24 19:56:30.027296
363 409,68,adam_cubiware,86,qbtest,"",user_created_repo,2012-07-24 19:56:30.040939
364 410,68,adam_cubiware,86,qbtest,"",push_local:04acb5b4d5e0baeedde09ab9f4921ebfd8a44fe3,2012-07-24 19:57:03.960782
365 411,68,adam_cubiware,87,fork-qbtest,"",started_following_repo,2012-07-24 19:57:49.226459
366 370,3,demo,,group/aaaaaa1,"",started_following_repo,2012-07-22 03:57:39.381977
367 371,3,demo,,group/aaaaaa1,"",user_created_repo,2012-07-22 03:57:39.394127
368 412,68,adam_cubiware,86,qbtest,"",user_forked_repo:fork-qbtest,2012-07-24 19:57:49.242082
369 413,68,adam_cubiware,87,fork-qbtest,"",user_created_fork:fork-qbtest,2012-07-24 19:57:49.249296
370 417,68,adam_cubiware,87,fork-qbtest,"",user_updated_repo,2012-07-24 20:01:54.283384
371 419,68,adam_cubiware,86,qbtest,"",user_commented_pull_request:13,2012-07-24 20:06:34.189996
372 414,68,adam_cubiware,87,fork-qbtest,"",push_local:8e189d16864ee66863e6153fd32b8ba3f2a25057,2012-07-24 19:58:20.712898
373 415,68,adam_cubiware,86,qbtest,"",user_commented_pull_request:13,2012-07-24 19:59:22.241511
374 418,68,adam_cubiware,86,qbtest,"",user_updated_repo,2012-07-24 20:02:57.048453
375 421,3,demo,87,fork-qbtest,"",user_commented_revision:8e189d16864ee66863e6153fd32b8ba3f2a25057,2012-07-24 20:11:04.301032
376 416,68,adam_cubiware,87,fork-qbtest,"",user_updated_repo,2012-07-24 20:01:41.416418
377 420,68,adam_cubiware,87,fork-qbtest,"",user_commented_revision:8e189d16864ee66863e6153fd32b8ba3f2a25057,2012-07-24 20:07:59.979705
378 422,3,demo,86,qbtest,"",user_commented_pull_request:13,2012-07-25 10:20:05.329183
379 423,3,demo,86,qbtest,"",user_commented_pull_request:13,2012-07-25 10:21:11.393746
380 424,3,demo,87,fork-qbtest,"",push_local:5556ddcc6f459ceaf3a5a305c56d3addd2ac7fb2,2012-07-25 10:22:50.053374
381 425,3,demo,87,fork-qbtest,"",user_commented_pull_request:14,2012-07-25 10:23:19.28703
382 426,3,demo,87,fork-qbtest,"",user_closed_pull_request:14,2012-07-25 10:23:19.294999
383 427,68,adam_cubiware,87,fork-qbtest,"",user_commented_revision:5556ddcc6f459ceaf3a5a305c56d3addd2ac7fb2,2012-07-25 10:26:23.952883
384 430,3,demo,86,qbtest,"",user_commented_pull_request:13,2012-07-25 10:28:09.672602
385 431,3,demo,86,qbtest,"",user_closed_pull_request:13,2012-07-25 10:28:09.683535
386 432,3,demo,86,qbtest,"",user_commented_pull_request:15,2012-07-25 15:04:21.750739
387 435,3,demo,86,qbtest,"",user_commented_pull_request:15,2012-07-25 15:05:29.409739
388 437,2,admin,87,fork-qbtest,"",user_commented_revision:8e189d16864ee66863e6153fd32b8ba3f2a25057,2012-07-25 15:06:24.177921
389 439,3,demo,86,qbtest,"",user_commented_pull_request:15,2012-07-25 15:06:58.589656
390 440,3,demo,34,a,"",user_updated_repo,2012-07-25 15:16:08.628588
391 441,3,demo,34,a,"",user_updated_repo,2012-07-25 15:16:50.160888
392 442,3,demo,34,a,"",user_updated_repo,2012-07-25 15:17:06.323596
393 443,3,demo,88,group/project-z,"",started_following_repo,2012-07-25 15:51:18.772615
394 444,3,demo,88,group/project-z,"",user_created_repo,2012-07-25 15:51:18.782868
395 445,3,demo,34,a,"",stopped_following_repo,2012-07-25 16:50:40.354634
396 446,3,demo,,Teszomg,"",started_following_repo,2012-07-25 16:58:00.642525
397 447,3,demo,,Teszomg,"",user_created_repo,2012-07-25 16:58:00.653681
398 448,3,demo,,Teszomg,"",user_deleted_repo,2012-07-25 17:00:13.827353
399 449,3,demo,90,a-fork1,"",started_following_repo,2012-07-25 17:52:15.778227
400 450,3,demo,34,a,"",user_forked_repo:a-fork1,2012-07-25 17:52:15.799024
401 451,3,demo,90,a-fork1,"",user_created_fork:a-fork1,2012-07-25 17:52:15.811638
402 452,3,demo,17,fork-test1,"",user_updated_repo,2012-07-25 18:30:05.412282
403 453,3,demo,91,SuperSolver,"",started_following_repo,2012-07-26 17:05:45.224827
404 454,3,demo,91,SuperSolver,"",user_created_repo,2012-07-26 17:05:45.238431
405 455,3,demo,91,SuperSolver,98.175.25.130,push:9191f84aab39f525a510865e8bfabdda11dd72a5,2012-07-26 17:09:12.133493
406 456,3,demo,92,group/kanad,"",started_following_repo,2012-07-26 21:11:56.38604
407 457,3,demo,92,group/kanad,"",user_created_repo,2012-07-26 21:11:56.400791
408 458,3,demo,92,group/kanad,"",user_updated_repo,2012-07-26 21:19:27.63466
409 459,2,admin,91,SuperSolver,"",push_local:466e4c17d8eda2789c5c885eeb376592f612c305,2012-07-26 22:17:43.023259
410 460,2,admin,91,SuperSolver,"",user_commented_revision:9191f84aab39f525a510865e8bfabdda11dd72a5,2012-07-26 22:18:16.224826
411 461,81,ahamilton,34,a,"",user_commented_revision:7f8b4f94e2a83394aa687e0bb110870769e9ca0a,2012-07-26 22:57:40.178759
412 462,1,default,34,a,54.247.183.89,pull,2012-07-26 23:14:42.710865
413 463,2,admin,34,a,"",admin_updated_repo,2012-07-27 01:33:24.257365
414 464,2,admin,56,brgit,"",admin_updated_repo,2012-07-27 01:33:54.214629
415 465,2,admin,93,fork-a,"",started_following_repo,2012-07-27 18:07:48.00309
416 466,2,admin,34,a,"",user_forked_repo:fork-a,2012-07-27 18:07:48.022053
417 467,2,admin,93,fork-a,"",user_created_fork:fork-a,2012-07-27 18:07:48.032889
418 468,2,admin,68,aaa-project,"",admin_updated_repo,2012-07-28 16:16:49.199267
419 469,2,admin,68,aaa-project,"",admin_updated_repo,2012-07-28 16:17:05.556031
420 470,2,admin,68,aaa-project,"",admin_updated_repo,2012-07-28 16:17:24.114857
421 471,2,admin,68,aaa-project,"",admin_updated_repo,2012-07-28 16:17:59.530129
422 472,2,admin,68,aaa-project,"",admin_updated_repo,2012-07-28 16:26:13.302324
423 473,2,admin,68,aaa-project,"",admin_updated_repo,2012-07-28 16:27:01.350536
424 474,86,gurce,,testies1.2.3,"",started_following_repo,2012-07-29 11:08:56.897379
425 475,86,gurce,,testies1.2.3,"",user_created_repo,2012-07-29 11:08:56.912364
426 476,86,gurce,,testies1.2.3,"",user_updated_repo,2012-07-29 11:14:02.439893
427 477,86,gurce,,testies1.2.3,"",user_deleted_repo,2012-07-29 11:18:46.488699
428 480,2,admin,,group/Linux,"",started_following_repo,2012-07-30 14:44:34.637639
429 481,2,admin,,group/Linux,"",admin_deleted_repo,2012-07-30 14:52:58.379429
430 482,3,demo,98,group/Another-Test-Repository,"",started_following_repo,2012-07-31 10:18:43.621644
431 483,3,demo,98,group/Another-Test-Repository,"",user_created_repo,2012-07-31 10:18:43.634721
432 484,3,demo,98,group/Another-Test-Repository,"",push_local:751faf9101afc1d11ce4c2a169991a17edbb7955,2012-07-31 10:19:46.035458
433 485,3,demo,98,group/Another-Test-Repository,"",user_updated_repo,2012-07-31 10:20:54.422059
434 486,3,demo,98,group/Another-Test-Repository,"",user_updated_repo,2012-07-31 10:21:47.573228
435 487,3,demo,98,group/Another-Test-Repository,"",stopped_following_repo,2012-07-31 10:22:43.12098
436 488,3,demo,98,group/Another-Test-Repository,"",started_following_repo,2012-07-31 10:22:48.801682
437 489,90,klaim,99,another-fork-to-check-code-review,"",started_following_repo,2012-07-31 14:25:57.394187
438 490,90,klaim,38,code-review-test,"",user_forked_repo:another-fork-to-check-code-review,2012-07-31 14:25:58.882735
439 491,90,klaim,99,another-fork-to-check-code-review,"",user_created_fork:another-fork-to-check-code-review,2012-07-31 14:25:58.889998
440 492,90,klaim,99,another-fork-to-check-code-review,"",user_commented_revision:c29efd2723954ba34fb63f9c7dce21a68b09715c,2012-07-31 14:27:39.427879
441 493,1,default,71,rkquery-fork,89.0.87.249,pull,2012-07-31 15:08:08.127006
442 494,1,default,71,rkquery-fork,89.0.87.249,pull,2012-07-31 15:08:37.692433
443 495,1,default,71,rkquery-fork,89.0.87.249,pull,2012-07-31 15:08:40.983571
444 496,3,demo,100,wurst,"",started_following_repo,2012-07-31 15:14:37.401815
445 497,3,demo,100,wurst,"",user_created_repo,2012-07-31 15:14:37.412923
446 498,1,default,100,wurst,89.0.87.249,pull,2012-07-31 15:14:45.754467
447 499,91,mzambrano,101,Prueba,"",started_following_repo,2012-07-31 17:04:41.872432
448 500,91,mzambrano,101,Prueba,"",user_created_repo,2012-07-31 17:04:41.883651
449 501,91,mzambrano,101,Prueba,"",push_local:9ecaa313dfd69d04eb99a6ab4650d5073d0979e0,2012-07-31 17:05:04.373838
450 506,3,demo,90,a-fork1,"",push_local:b09d43f798414bcbdf4dc1fc5dafe6ce4aa5afc3,2012-08-01 03:18:34.613972
451 507,3,demo,90,a-fork1,"",user_updated_repo,2012-08-01 03:19:21.260608
452 508,3,demo,34,a,"",user_commented_pull_request:16,2012-08-01 03:20:55.082899
453 509,3,demo,34,a,"",user_closed_pull_request:16,2012-08-01 03:20:55.089597
454 510,3,demo,34,a,"",user_commented_pull_request:17,2012-08-01 03:24:44.63976
455 511,3,demo,41,fork-code-review-test1111111,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-08-01 18:56:56.755186
456 512,3,demo,41,fork-code-review-test1111111,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-08-01 18:57:03.502595
457 478,86,gurce,,aaa,"",started_following_repo,2012-07-29 11:19:09.137514
458 479,86,gurce,,aaa,"",user_created_repo,2012-07-29 11:19:09.151528
459 513,15,Vipous,25,My1,"",push_local:50e642196270635f02c5bd5c00e499dc187178df,2012-08-01 19:11:17.87993
460 514,1,default,25,My1,95.24.51.243,pull,2012-08-01 19:15:28.508852
461 515,15,Vipous,25,my1,"",user_updated_repo,2012-08-01 19:32:20.993611
462 516,15,Vipous,103,my2,"",started_following_repo,2012-08-01 19:38:38.060511
463 517,15,Vipous,103,my2,"",user_created_repo,2012-08-01 19:38:38.069864
464 518,15,Vipous,103,my2,"",user_updated_repo,2012-08-01 19:45:16.160287
465 519,15,Vipous,103,my2,"",user_updated_repo,2012-08-01 19:46:04.886008
466 520,15,Vipous,104,m3,"",started_following_repo,2012-08-01 19:46:48.535281
467 521,15,Vipous,104,m3,"",user_created_repo,2012-08-01 19:46:48.549938
468 522,15,Vipous,104,m3,"",user_updated_repo,2012-08-01 19:47:15.299734
469 523,95,vladest,105,group/MainCa,"",started_following_repo,2012-08-02 11:30:01.303239
470 524,95,vladest,105,group/MainCa,"",user_created_repo,2012-08-02 11:30:01.314496
471 525,95,vladest,105,group/MainCa,"",push_local:d43c6b4b865d2c37ac9bb8300ed2594f5c7bfac1,2012-08-02 11:32:35.723828
472 526,95,vladest,106,group/MainCa1,"",started_following_repo,2012-08-02 12:20:15.170113
473 527,95,vladest,106,group/MainCa1,"",user_created_repo,2012-08-02 12:20:15.178842
474 528,97,Cykooz,107,TestRep,"",started_following_repo,2012-08-02 14:19:22.221295
475 529,97,Cykooz,107,TestRep,"",user_created_repo,2012-08-02 14:19:22.233832
476 530,97,Cykooz,107,TestRep,"",push_local:d15f2b728cbe3d99cdb87847252245defb65af97,2012-08-02 14:20:54.178448
477 532,3,demo,1,test,"",user_commented_revision:ef02269209cd431c0cd0ee929ba37ae895651d69,2012-08-03 10:06:58.707278
478 533,3,demo,108,pouet_toto,"",started_following_repo,2012-08-03 10:39:59.081678
479 534,3,demo,108,pouet_toto,"",user_created_repo,2012-08-03 10:39:59.093405
480 535,1,default,107,TestRep,195.238.92.121,pull,2012-08-03 17:59:06.989454
481 538,3,demo,110,django,"",started_following_repo,2012-08-03 19:18:45.155897
482 539,3,demo,110,django,"",user_created_repo,2012-08-03 19:18:45.172636
483 540,3,demo,90,a-fork1,"",user_commented_revision:b09d43f798414bcbdf4dc1fc5dafe6ce4aa5afc3,2012-08-03 19:33:48.041371
484 541,102,floris1988,111,TestSpecialChars-Γ―,"",started_following_repo,2012-08-04 18:53:17.2228
485 542,102,floris1988,111,TestSpecialChars-Γ―,"",user_created_repo,2012-08-04 18:53:17.234721
486 543,102,floris1988,111,TestSpecialChars-Γ―,"",user_updated_repo,2012-08-04 18:53:50.060979
487 544,102,floris1988,111,TestSpecialChars-Γ―,"",user_updated_repo,2012-08-04 18:55:53.495862
488 545,3,demo,112,segaja_test,"",started_following_repo,2012-08-04 19:04:06.239802
489 546,3,demo,112,segaja_test,"",user_created_repo,2012-08-04 19:04:06.253287
490 547,3,demo,112,segaja_test,92.224.13.159,push:42e459600bdbd38d1faf6eaa10c7e01c56cd10f9,2012-08-04 19:29:14.690831
491 548,1,default,112,segaja_test,92.224.252.14,pull,2012-08-04 19:34:36.973664
492 549,3,demo,113,fork-big-project-test,"",started_following_repo,2012-08-05 02:55:27.385395
493 550,3,demo,32,big-project,"",user_forked_repo:fork-big-project-test,2012-08-05 02:55:27.414409
494 551,3,demo,113,fork-big-project-test,"",user_created_fork:fork-big-project-test,2012-08-05 02:55:27.4288
495 552,2,admin,,zaraza,"",admin_deleted_repo,2012-08-05 13:27:42.970283
496 553,2,admin,,asd,"",admin_deleted_repo,2012-08-05 13:28:00.428749
497 536,3,demo,,short,"",started_following_repo,2012-08-03 18:03:15.665115
498 537,3,demo,,short,"",user_created_repo,2012-08-03 18:03:15.67758
499 554,2,admin,,short,"",admin_deleted_repo,2012-08-05 13:28:31.888167
500 555,2,admin,,rune-test,"",admin_deleted_repo,2012-08-05 13:28:37.66319
501 556,2,admin,,test2,"",admin_deleted_repo,2012-08-05 13:29:14.388401
502 502,3,demo,,test1771,"",started_following_repo,2012-07-31 23:21:17.003832
503 503,3,demo,,test1771,"",user_created_repo,2012-07-31 23:21:17.01404
504 504,3,demo,,test1771,"",user_updated_repo,2012-07-31 23:22:03.144832
505 505,3,demo,,test1771,"",user_updated_repo,2012-07-31 23:22:24.167363
506 557,2,admin,,test1771,"",admin_deleted_repo,2012-08-05 13:29:38.632652
507 558,2,admin,,aaa,"",admin_deleted_repo,2012-08-05 13:30:03.546834
508 359,3,demo,,group/aaaaa,"",started_following_repo,2012-07-21 03:38:35.138131
509 360,3,demo,,group/aaaaa,"",user_created_repo,2012-07-21 03:38:35.15336
510 361,3,demo,,group/aaaaa,"",stopped_following_repo,2012-07-21 03:40:17.083354
511 559,2,admin,,group/aaaaa,"",admin_deleted_repo,2012-08-05 13:30:13.234414
512 560,2,admin,,group/aaaaaa1,"",admin_deleted_repo,2012-08-05 13:30:18.727572
513 561,3,demo,114,repo1,"",started_following_repo,2012-08-05 22:24:30.710387
514 562,3,demo,114,repo1,"",user_created_repo,2012-08-05 22:24:30.720533
515 563,3,demo,114,repo1,"",user_updated_repo,2012-08-05 22:25:03.129876
516 564,3,demo,114,group/repo1,"",user_updated_repo,2012-08-06 01:33:29.413213
517 565,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:d5422faf648cc589425cd3b0dbf1f6dbf93036a0,2012-08-06 12:41:54.182248
518 566,3,demo,115,seva,"",started_following_repo,2012-08-06 13:50:43.115804
519 567,3,demo,115,seva,"",user_created_repo,2012-08-06 13:50:43.129954
520 568,3,demo,115,seva,94.28.52.54,push:06a5a7a52876f01f458a2f816320bab5bafc8cb7,2012-08-06 14:05:42.593075
521 569,3,demo,116,sr_Types,"",started_following_repo,2012-08-06 14:10:07.910072
522 570,3,demo,116,sr_Types,"",user_created_repo,2012-08-06 14:10:07.917777
523 571,3,demo,116,sr_Types,94.28.52.54,"push:82f049910f50a5f21af4e097ff143cffc40ed24b,744a1af870e28684381d6dbc49fc3ee8e84bd037,c4e4c1f60bf9c35ddb6b3b244e3ac653bf9013fb,6243a66ba6f45ae7019b785e34c87415c75f0100,f98dabdf9d6721c9cb2ce951473602261b197572",2012-08-06 14:11:06.205283
524 572,3,demo,117,group/PersTest,"",started_following_repo,2012-08-07 13:56:12.405578
525 573,3,demo,117,group/PersTest,"",user_created_repo,2012-08-07 13:56:12.425432
526 574,3,demo,118,group/fork-PersTest11111,"",started_following_repo,2012-08-07 16:19:34.151798
527 575,3,demo,117,group/PersTest,"",user_forked_repo:group/fork-PersTest11111,2012-08-07 16:19:35.508635
528 576,3,demo,118,group/fork-PersTest11111,"",user_created_fork:group/fork-PersTest11111,2012-08-07 16:19:35.521466
529 577,3,demo,119,group/fork-PersTesttest23,"",started_following_repo,2012-08-07 16:21:38.613229
530 578,3,demo,117,group/PersTest,"",user_forked_repo:group/fork-PersTesttest23,2012-08-07 16:21:39.912103
531 579,3,demo,119,group/fork-PersTesttest23,"",user_created_fork:group/fork-PersTesttest23,2012-08-07 16:21:39.925959
532 580,3,demo,120,group/clojure.git,"",started_following_repo,2012-08-07 16:23:44.191686
533 581,3,demo,120,group/clojure.git,"",user_created_repo,2012-08-07 16:23:44.209175
534 582,3,demo,121,group/fork-clojure.git11111,"",started_following_repo,2012-08-07 16:23:59.92049
535 583,3,demo,120,group/clojure.git,"",user_forked_repo:group/fork-clojure.git11111,2012-08-07 16:24:01.272504
536 584,3,demo,121,group/fork-clojure.git11111,"",user_created_fork:group/fork-clojure.git11111,2012-08-07 16:24:01.286295
537 585,3,demo,121,group/fork-clojure.git11111,"",user_updated_repo,2012-08-07 16:25:08.111886
538 586,3,demo,117,group/PersTest,"",user_commented_revision:3823d29c041a56af5d798e1bf308169635b307b2,2012-08-07 16:33:30.109982
539 587,3,demo,117,group/PersTest,"",user_commented_revision:3823d29c041a56af5d798e1bf308169635b307b2,2012-08-07 16:33:47.039431
540 588,3,demo,117,group/PersTest,"",push_local:cc8900b3722b55c4435ccf5c14cf4883c62ebdb1,2012-08-07 16:34:33.016369
541 589,1,default,34,a,75.69.241.64,pull,2012-08-07 16:45:32.904556
542 590,3,demo,122,amab,"",started_following_repo,2012-08-08 18:51:41.487459
543 591,3,demo,122,amab,"",user_created_repo,2012-08-08 18:51:41.502954
544 592,3,demo,123,fork-amab,"",started_following_repo,2012-08-08 18:52:54.7185
545 593,3,demo,122,amab,"",user_forked_repo:fork-amab,2012-08-08 18:52:54.735201
546 594,3,demo,123,fork-amab,"",user_created_fork:fork-amab,2012-08-08 18:52:54.747165
547 595,108,dukeofgaming,124,fork-another-fork-to-check-code-review,"",started_following_repo,2012-08-08 20:20:04.849671
548 596,108,dukeofgaming,99,another-fork-to-check-code-review,"",user_forked_repo:fork-another-fork-to-check-code-review,2012-08-08 20:20:04.90856
549 597,108,dukeofgaming,124,fork-another-fork-to-check-code-review,"",user_created_fork:fork-another-fork-to-check-code-review,2012-08-08 20:20:04.916268
550 598,108,dukeofgaming,125,test-to-end-all-tests,"",started_following_repo,2012-08-08 20:24:44.691886
551 599,108,dukeofgaming,125,test-to-end-all-tests,"",user_created_repo,2012-08-08 20:24:44.701816
552 600,108,dukeofgaming,125,test-to-end-all-tests,"",push_local:fb4eb182028a674ae250430c04305e9b3fbe508e,2012-08-08 20:26:27.345121
553 601,108,dukeofgaming,34,a,"",user_commented_pull_request:17,2012-08-08 21:57:59.006296
554 602,109,StrangeWill,126,StrangeWill-Test,"",started_following_repo,2012-08-09 02:34:52.271872
555 603,109,StrangeWill,126,StrangeWill-Test,"",user_created_repo,2012-08-09 02:34:52.282934
556 604,109,StrangeWill,126,StrangeWill-Test,"",user_updated_repo,2012-08-09 02:35:02.383584
557 605,109,StrangeWill,126,StrangeWill-Test,"",user_updated_repo,2012-08-09 02:35:06.402314
558 606,109,StrangeWill,126,StrangeWill-Test,"",push_local:9c53f740e08b8bbc51bb3c44b1daab9f52287d3a,2012-08-09 02:35:43.942575
559 607,109,StrangeWill,126,StrangeWill-Test,"",user_commented_pull_request:19,2012-08-09 02:36:48.962911
560 608,109,StrangeWill,126,StrangeWill-Test,"",user_closed_pull_request:19,2012-08-09 02:36:48.968935
561 609,3,demo,1,test,"",user_commented_pull_request:20,2012-08-10 11:23:48.112425
562 610,3,demo,1,test,"",user_closed_pull_request:20,2012-08-10 11:23:48.122186
563 611,3,demo,8,Test_Repo,"",user_commented_pull_request:12,2012-08-10 11:29:38.483128
564 612,3,demo,8,Test_Repo,"",user_commented_pull_request:12,2012-08-10 11:29:48.326018
565 613,3,demo,8,Test_Repo,"",user_closed_pull_request:12,2012-08-10 11:29:48.336563
566 614,3,demo,34,a,"",user_commented_pull_request:18,2012-08-10 11:32:01.569982
567 615,2,admin,,"","",admin_created_users_group:group,2012-08-10 20:13:05.655137
568 616,3,demo,122,amab,"",push_local:86b1fc3a3f5dc193814327817d2274dc2e25aa74,2012-08-11 05:48:36.958893
569 617,3,demo,122,amab,"",user_commented_revision:86b1fc3a3f5dc193814327817d2274dc2e25aa74,2012-08-11 05:49:10.966918
570 618,3,demo,122,amab,"",push_local:8530d8e3eab04997ac4a2a5d8a8b54fa61bb9884,2012-08-11 05:50:15.022811
571 619,3,demo,127,my-super-rep,"",started_following_repo,2012-08-11 12:30:55.461553
572 620,3,demo,127,my-super-rep,"",user_created_repo,2012-08-11 12:30:55.490584
573 621,3,demo,127,my-super-rep,"",push_local:5d80e28538141e322b317168e2367fb03178d58c,2012-08-11 12:32:07.883859
574 622,3,demo,127,my-super-rep,"",user_updated_repo,2012-08-11 12:33:26.213226
575 623,3,demo,124,fork-another-fork-to-check-code-review,"",user_commented_revision:d5422faf648cc589425cd3b0dbf1f6dbf93036a0,2012-08-11 15:07:59.546001
576 624,3,demo,29,otro-test,"",push_local:84da67001150cd0bf3ef744c286bcc432ea21bd4,2012-08-11 15:33:05.169706
577 625,1,default,81,FS_dummy,66.85.224.48,pull,2012-08-11 19:31:31.664606
578 626,3,demo,128,testprivate,"",started_following_repo,2012-08-12 10:25:42.265395
579 627,3,demo,128,testprivate,"",user_created_repo,2012-08-12 10:25:42.278839
580 628,3,demo,128,testprivate,"",user_updated_repo,2012-08-12 10:27:29.467173
581 629,3,demo,128,testprivate,"",user_updated_repo,2012-08-12 10:28:09.878656
582 630,3,demo,128,group/testprivate,"",user_updated_repo,2012-08-12 10:29:00.702759
583 631,3,demo,128,group/testprivate,"",push_local:a7e9cdbd374255258a2d470dae64142c62577e62,2012-08-12 10:32:28.350191
584 632,3,demo,54,glib,"",user_commented_revision:eda1735029e01d6391fe8a4cde6c5688727c8183,2012-08-12 15:21:32.004992
585 633,3,demo,54,glib,"",user_commented_revision:eda1735029e01d6391fe8a4cde6c5688727c8183,2012-08-12 15:21:56.235395
586 634,3,demo,129,dvorak,"",started_following_repo,2012-08-12 15:23:37.292086
587 635,3,demo,129,dvorak,"",user_created_repo,2012-08-12 15:23:37.302785
588 636,3,demo,129,dvorak,202.147.201.173,pull,2012-08-12 15:24:08.62022
589 637,3,demo,130,x,"",started_following_repo,2012-08-12 23:37:03.115333
590 638,3,demo,130,x,"",user_created_repo,2012-08-12 23:37:03.130599
591 639,3,demo,124,fork-another-fork-to-check-code-review,"",user_commented_revision:8b7cd9a998f0f4ec47cf75b59b3d2c08167c3cf7,2012-08-12 23:39:33.305222
592 640,3,demo,44,diff-test,"",user_commented_revision:50daf150549b8d48676889dcb713f1f4e0e4bc9d,2012-08-13 05:24:22.678285
593 641,3,demo,123,fork-amab,"",push_local:6a6a5d929be9b4929041627d35f18627d9418aa5,2012-08-13 10:53:50.793419
594 642,1,default,57,SuperProject,128.237.226.40,pull,2012-08-13 16:07:22.373945
595 643,3,demo,34,a,"",user_commented_pull_request:24,2012-08-13 19:43:04.754874
596 644,3,demo,34,a,"",user_closed_pull_request:24,2012-08-13 19:43:04.765323
597 645,3,demo,34,a,"",user_commented_pull_request:25,2012-08-13 19:45:34.763703
598 646,3,demo,34,a,"",user_closed_pull_request:25,2012-08-13 19:45:34.769014
599 647,3,demo,131,group/test-v,"",started_following_repo,2012-08-13 19:46:36.628573
600 648,3,demo,131,group/test-v,"",user_created_repo,2012-08-13 19:46:36.637409
601 649,3,demo,131,group/test-v,"",push_local:5528f3d665c9c9577670ec1e47428ec12686309e,2012-08-13 19:46:57.911585
602 650,3,demo,132,test-alex,"",started_following_repo,2012-08-13 21:21:05.904895
603 651,3,demo,132,test-alex,"",user_created_repo,2012-08-13 21:21:05.916732
604 652,3,demo,132,test-alex,"",push_local:016bda6a3079ea1d69b6a309a9ecc61fe5b671df,2012-08-13 21:21:34.951309
605 653,3,demo,132,test-alex,"",user_commented_revision:016bda6a3079ea1d69b6a309a9ecc61fe5b671df,2012-08-13 21:22:06.758798
606 654,3,demo,132,test-alex,"",push_local:7f43f5167e26a3e43e6ad0ac6539ab4c8589a509,2012-08-13 21:22:18.07678
607 655,3,demo,132,test-alex,"",user_commented_revision:7f43f5167e26a3e43e6ad0ac6539ab4c8589a509,2012-08-13 21:22:39.209522
608 656,3,demo,132,test-alex,"",push_local:9b754ec30decff4c11c0f82522b7ec9dd732b738,2012-08-13 21:23:44.132906
609 657,3,demo,132,test-alex,"",user_commented_revision:9b754ec30decff4c11c0f82522b7ec9dd732b738,2012-08-13 21:24:34.975113
610 658,3,demo,132,test-alex,"",push_local:625c046f35779ccde8c2284ee60fda3d9598e8bb,2012-08-13 21:25:07.493234
611 659,3,demo,132,test-alex,"",push_local:807dd6bb60f5eef82f7ffdd988dee3e0de4e44dc,2012-08-13 21:26:51.764858
612 660,3,demo,132,test-alex,"",push_local:24224f94a8578508883f58982e10b0ffa83a98d6,2012-08-13 21:28:03.831471
613 661,3,demo,42,foo,"",user_commented_revision:ca953e8c5c1ada44e9a8f945a0a6999d2f44310d,2012-08-14 18:40:46.618059
614 662,118,peso-rhodecode,99,another-fork-to-check-code-review,"",user_commented_revision:30853f4bde2f2b6f0a7126392b9b1b4c5ea37e0a,2012-08-14 18:58:56.536013
615 663,118,peso-rhodecode,99,another-fork-to-check-code-review,"",user_commented_revision:30853f4bde2f2b6f0a7126392b9b1b4c5ea37e0a,2012-08-14 18:59:58.982696
616 664,118,peso-rhodecode,133,tortoisehg,"",started_following_repo,2012-08-14 19:05:14.873877
617 665,118,peso-rhodecode,133,tortoisehg,"",user_created_repo,2012-08-14 19:05:14.88921
618 666,119,ricardona,39,fork-code-review-test,"",user_commented_revision:ac19ef61aab0b008acb5dac5d53457cbd278d927,2012-08-14 21:20:28.585574
619 667,3,demo,134,TestIM,"",started_following_repo,2012-08-14 22:23:05.22279
620 668,3,demo,134,TestIM,"",user_created_repo,2012-08-14 22:23:05.235172
621 669,3,demo,134,TestIM,216.16.228.6,push:b3b6cfdb515f13709b13f82d20efd74daaa11d91,2012-08-14 22:23:54.286624
622 670,3,demo,134,TestIM,216.16.228.6,push:9fb9ba572906576b2cc53ac227d503317f019556,2012-08-14 22:24:48.190215
623 671,3,demo,134,TestIM,"",user_commented_pull_request:26,2012-08-14 22:25:32.752851
624 672,3,demo,134,TestIM,"",user_commented_pull_request:26,2012-08-14 22:26:29.238006
625 673,3,demo,134,TestIM,"",user_closed_pull_request:26,2012-08-14 22:26:29.246245
626 674,3,demo,134,TestIM,216.16.228.6,push:55a4fabac6221f988a276ec34343b947dfbc8a1f,2012-08-14 22:35:56.966751
627 676,120,asdfqwer,135,Asdf,"",started_following_repo,2012-08-15 01:25:41.462335
628 677,120,asdfqwer,135,Asdf,"",user_created_repo,2012-08-15 01:25:41.473404
629 678,120,asdfqwer,135,Asdf,"",push_local:e43db28406d1d0697f504af9bc2ae5c5b789bba3,2012-08-15 01:27:34.991
630 679,3,demo,68,aaa-project,"",push_local:2babd97db425482a53b679956df09f89c3154a2c,2012-08-15 03:43:31.538895
631 680,3,demo,134,TestIM,"",user_commented_revision:55a4fabac6221f988a276ec34343b947dfbc8a1f,2012-08-15 14:30:08.564118
632 681,3,demo,134,TestIM,"",user_commented_pull_request:27,2012-08-15 14:30:18.831116
633 682,3,demo,134,TestIM,"",user_closed_pull_request:27,2012-08-15 14:30:18.840491
634 683,3,demo,134,TestIM,216.16.228.6,push:bb4219af072d59cc4c3c43c378ed51fa4cf3c3ff,2012-08-15 15:07:41.727749
635 684,1,default,131,group/test-v,24.226.1.232,pull,2012-08-15 16:55:41.900521
636 685,3,demo,131,group/test-v,"",user_commented_revision:5528f3d665c9c9577670ec1e47428ec12686309e,2012-08-15 17:03:55.63388
637 686,1,default,131,group/test-v,24.226.1.232,pull,2012-08-15 17:08:29.295025
638 687,1,default,131,group/test-v,24.226.1.232,pull,2012-08-15 17:29:40.060992
639 688,1,default,131,group/test-v,24.226.1.232,pull,2012-08-15 17:33:06.514696
640 689,1,default,131,group/test-v,24.226.1.232,pull,2012-08-15 17:35:45.952417
641 690,1,default,131,group/test-v,24.226.1.232,pull,2012-08-15 17:45:52.189501
642 691,1,default,131,group/test-v,24.226.1.232,pull,2012-08-15 18:15:01.771261
643 692,3,demo,136,demorep,"",started_following_repo,2012-08-15 20:15:43.960506
644 693,3,demo,136,demorep,"",user_created_repo,2012-08-15 20:15:43.97291
645 694,3,demo,136,demorep,"",user_updated_repo,2012-08-15 20:16:36.235636
646 695,116,japanfred,137,group/test,"",started_following_repo,2012-08-16 10:07:53.071203
647 696,116,japanfred,137,group/test,"",user_created_repo,2012-08-16 10:07:53.085238
648 697,3,demo,38,code-review-test,"",user_commented_revision:e780fb37168be5382148f5bc6fd420ae9771e947,2012-08-16 10:40:09.850092
649 698,3,demo,38,code-review-test,"",user_commented_revision:e780fb37168be5382148f5bc6fd420ae9771e947,2012-08-16 10:40:18.256489
650 699,3,demo,138,zzz,"",started_following_repo,2012-08-16 15:32:36.358347
651 700,3,demo,138,zzz,"",user_created_repo,2012-08-16 15:32:36.375112
652 701,3,demo,138,zzz,"",stopped_following_repo,2012-08-16 15:32:47.449322
653 702,3,demo,138,zzz,"",push_local:30c34a6a74a3acb1ac90da14cbf5afc195c06703,2012-08-16 15:35:02.210691
654 703,3,demo,139,groupv,"",started_following_repo,2012-08-16 21:18:09.813691
655 704,3,demo,139,groupv,"",user_created_repo,2012-08-16 21:18:09.828768
656 705,3,demo,140,tryit,"",started_following_repo,2012-08-16 21:38:23.244914
657 706,3,demo,140,tryit,"",user_created_repo,2012-08-16 21:38:23.255027
658 707,3,demo,24,fork-Something,"",push_local:3e4a3d2cb39cc292337813a1b66886612967a12f,2012-08-17 08:46:15.254412
659 708,125,thebodster,141,benltest,"",started_following_repo,2012-08-17 11:05:03.588299
660 709,125,thebodster,141,benltest,"",user_created_repo,2012-08-17 11:05:03.599788
661 710,125,thebodster,141,benltest,"",push_local:81058e0bbe3ff64719b622da3e3d4973a00aa17f,2012-08-17 11:06:28.089348
662 711,3,demo,142,asd,"",started_following_repo,2012-08-17 17:05:25.612621
663 712,3,demo,142,asd,"",user_created_repo,2012-08-17 17:05:25.623665
664 713,3,demo,90,a-fork1,"",user_commented_revision:5478c7d290bc0a14d9cefd79ed5722a87f3815d5,2012-08-20 11:55:54.518151
665 714,3,demo,90,a-fork1,"",user_commented_revision:5478c7d290bc0a14d9cefd79ed5722a87f3815d5,2012-08-20 11:56:13.790927
666 715,3,demo,34,a,"",user_commented_revision:7ec6b566916b553f8ab92aaf1c993269b96b52ee,2012-08-20 12:15:53.217431
667 716,3,demo,143,collabo-test,"",started_following_repo,2012-08-20 14:26:09.569571
668 717,3,demo,143,collabo-test,"",user_created_repo,2012-08-20 14:26:09.582085
669 718,3,demo,143,collabo-test,"",user_updated_repo,2012-08-20 14:32:35.45571
670 719,3,demo,143,group/collabo-test,"",user_updated_repo,2012-08-20 14:34:12.224005
671 720,3,demo,143,group/collabo-test,"",user_updated_repo,2012-08-20 14:38:00.881804
672 721,3,demo,143,group/collabo-test,"",user_updated_repo,2012-08-20 14:38:55.248397
673 722,131,edroi,144,group/testing_repo_ed,"",started_following_repo,2012-08-20 17:52:56.864724
674 723,131,edroi,144,group/testing_repo_ed,"",user_created_repo,2012-08-20 17:52:56.875807
675 724,3,demo,145,group/test001,"",started_following_repo,2012-08-21 12:04:31.34427
676 725,3,demo,145,group/test001,"",user_created_repo,2012-08-21 12:04:31.361085
677 726,3,demo,145,group/test001,"",push_local:be9945bab2129191dcfe7c3cf1530c953cb56250,2012-08-21 12:06:07.781578
678 727,2,admin,34,a,"",user_commented_revision:7f8b4f94e2a83394aa687e0bb110870769e9ca0a,2012-08-21 12:09:46.857288
679 728,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-08-22 10:25:41.344244
680 729,3,demo,146,group/sjhasgdasgd,"",started_following_repo,2012-08-22 10:27:23.865563
681 730,3,demo,146,group/sjhasgdasgd,"",user_created_repo,2012-08-22 10:27:23.879703
682 731,134,asdf1234,,master-work,"",started_following_repo,2012-08-22 15:42:30.690987
683 732,134,asdf1234,,master-work,"",user_created_repo,2012-08-22 15:42:30.701316
684 733,134,asdf1234,,master-work,"",push_local:9a0c3c1f07d0d53f4578048e64ee7460540a8650,2012-08-22 15:42:51.105132
685 734,134,asdf1234,,master-work,"",user_deleted_repo,2012-08-22 15:43:40.616875
686 740,3,demo,122,amab,"",user_commented_revision:8530d8e3eab04997ac4a2a5d8a8b54fa61bb9884,2012-08-22 15:55:10.054525
687 735,134,asdf1234,,Master-Repo,"",started_following_repo,2012-08-22 15:44:00.955916
688 736,134,asdf1234,,Master-Repo,"",user_created_repo,2012-08-22 15:44:00.969061
689 737,134,asdf1234,,Master-Repo,198.47.12.251,push:511c6906e2dfcfdcf8e616705c4021250ce9317c,2012-08-22 15:47:31.882017
690 738,134,asdf1234,,Master-Repo,"",user_updated_repo,2012-08-22 15:48:13.441863
691 739,134,asdf1234,,Master-Repo,198.47.12.251,push:650eab8084b7194849c714a7b8ee624ccb143961,2012-08-22 15:55:02.593373
692 741,1,default,,Master-Repo,176.9.28.203,pull,2012-08-22 15:55:55.777458
693 749,134,asdf1234,,Master-Repo,"",user_deleted_repo,2012-08-22 16:04:45.631529
694 746,134,asdf1234,,Master-repo-my-work,"",started_following_repo,2012-08-22 16:03:30.002885
695 747,134,asdf1234,,Master-repo-my-work,"",user_created_repo,2012-08-22 16:03:30.014977
696 748,134,asdf1234,,Master-repo-my-work,198.47.12.251,"push:511c6906e2dfcfdcf8e616705c4021250ce9317c,650eab8084b7194849c714a7b8ee624ccb143961,9e9ec10c23b2d7906221296e9b824e09aca4d135",2012-08-22 16:03:46.33517
697 750,134,asdf1234,,Master-repo-my-work,"",user_deleted_repo,2012-08-22 16:04:52.44082
698 742,134,asdf1234,,Master-Repo-work,"",started_following_repo,2012-08-22 15:55:55.950145
699 743,134,asdf1234,,Master-Repo-work,"",user_created_repo,2012-08-22 15:55:55.964648
700 744,1,default,,Master-Repo-work,198.47.12.251,pull,2012-08-22 15:56:19.314483
701 745,134,asdf1234,,Master-Repo-work,198.47.12.251,push:9e9ec10c23b2d7906221296e9b824e09aca4d135,2012-08-22 15:57:15.289776
702 751,134,asdf1234,,Master-Repo-work,"",user_deleted_repo,2012-08-22 16:05:17.555968
703 752,3,demo,90,a-fork1,"",user_commented_revision:5478c7d290bc0a14d9cefd79ed5722a87f3815d5,2012-08-22 16:55:58.931518
704 753,3,demo,88,group/project-z,"",user_updated_repo,2012-08-24 11:32:31.148489
705 754,3,demo,151,group/test2,"",started_following_repo,2012-08-24 15:44:04.072312
706 755,3,demo,151,group/test2,"",user_created_repo,2012-08-24 15:44:04.088381
707 756,3,demo,34,a,"",push_local:332932afc11a2c6308d44e75f8b4ac7643093fa7,2012-08-24 17:15:46.470802
708 757,136,buk,152,group/create_test,"",started_following_repo,2012-08-25 06:40:04.917748
709 758,136,buk,152,group/create_test,"",user_created_repo,2012-08-25 06:40:04.931544
710 759,136,buk,121,group/fork-clojure.git11111,"",user_updated_repo,2012-08-25 06:42:39.902167
711 760,140,ryanewtaylor,153,my_test_repository,"",started_following_repo,2012-08-27 03:06:53.764986
712 761,140,ryanewtaylor,153,my_test_repository,"",user_created_repo,2012-08-27 03:06:53.777712
713 763,140,ryanewtaylor,153,my_test_repository,"",user_commented_revision:adca53fe04fd153232ba0f2b0849593d7e7e66b3,2012-08-27 03:13:37.332593
714 764,140,ryanewtaylor,153,my_test_repository,"",user_commented_revision:adca53fe04fd153232ba0f2b0849593d7e7e66b3,2012-08-27 03:14:12.752967
715 765,140,ryanewtaylor,153,my_test_repository,"",user_commented_revision:adca53fe04fd153232ba0f2b0849593d7e7e66b3,2012-08-27 03:14:51.684298
716 766,140,ryanewtaylor,153,my_test_repository,"",user_commented_revision:6669f75a9cb677a2fda670b38b1144148ebeb962,2012-08-27 03:15:12.583256
717 767,140,ryanewtaylor,153,my_test_repository,"",user_commented_revision:df1618708e7fa0c17d5f6b45c20862c22ddec32e,2012-08-27 03:16:16.068448
718 768,140,ryanewtaylor,153,my_test_repository,"",user_commented_revision:df1618708e7fa0c17d5f6b45c20862c22ddec32e,2012-08-27 03:16:21.558262
719 769,2,admin,153,my_test_repository,"",user_commented_revision:6669f75a9cb677a2fda670b38b1144148ebeb962,2012-08-27 09:57:00.382062
720 770,141,asdf1234asdf,93,fork-a,"",user_commented_pull_request:29,2012-08-28 00:15:33.186954
721 771,141,asdf1234asdf,93,fork-a,"",user_closed_pull_request:29,2012-08-28 00:15:33.199962
722 773,143,demodemo1,93,fork-a,"",user_commented_revision:7f8b4f94e2a83394aa687e0bb110870769e9ca0a,2012-08-29 09:44:47.573503
723 774,3,demo,90,a-fork1,"",push_local:323f852b71ad55dde8b5134ecab08d38e478a2c5,2012-08-29 11:07:26.784421
724 775,116,japanfred,156,jf-main,"",started_following_repo,2012-08-29 14:07:27.6853
725 776,116,japanfred,156,jf-main,"",user_created_repo,2012-08-29 14:07:27.698708
726 777,116,japanfred,156,jf-main,"",push_local:3da6f8032b842427e3873733bc997cc38870028c,2012-08-29 14:08:26.649182
727 778,116,japanfred,156,group/jf-main,"",user_updated_repo,2012-08-29 14:08:51.803377
728 779,145,fthomas64,157,group/fintest,"",started_following_repo,2012-08-29 21:54:55.55875
729 780,145,fthomas64,157,group/fintest,"",user_created_repo,2012-08-29 21:54:55.5727
730 781,145,fthomas64,157,group/fintest,"",user_updated_repo,2012-08-29 21:56:46.846955
731 782,3,demo,158,mytest001,"",started_following_repo,2012-08-29 23:38:29.423035
732 783,3,demo,158,mytest001,"",user_created_repo,2012-08-29 23:38:29.434528
733 784,3,demo,158,mytest001,"",user_updated_repo,2012-08-29 23:40:30.218875
734 785,3,demo,158,mytest001,"",push_local:877dd37e0d11c11006ba333eea74972f8f3c0745,2012-08-29 23:56:55.750242
735 786,3,demo,158,mytest001,"",user_commented_revision:877dd37e0d11c11006ba333eea74972f8f3c0745,2012-08-29 23:57:17.769527
736 787,3,demo,158,mytest001,"",user_commented_revision:877dd37e0d11c11006ba333eea74972f8f3c0745,2012-08-30 00:00:06.214755
737 788,3,demo,86,qbtest,"",user_commented_revision:04acb5b4d5e0baeedde09ab9f4921ebfd8a44fe3,2012-08-30 18:18:52.127137
738 789,3,demo,86,qbtest,"",user_commented_revision:04acb5b4d5e0baeedde09ab9f4921ebfd8a44fe3,2012-08-30 18:19:39.559827
739 790,3,demo,159,group/Test-for-code-review,"",started_following_repo,2012-08-30 18:21:15.38201
740 791,3,demo,159,group/Test-for-code-review,"",user_created_repo,2012-08-30 18:21:15.396876
741 792,3,demo,159,group/Test-for-code-review,"",push_local:2305443e5a06a9d80e328741d2da742145f80eee,2012-08-30 18:22:30.576129
742 793,3,demo,159,group/Test-for-code-review,"",user_commented_revision:2305443e5a06a9d80e328741d2da742145f80eee,2012-08-30 18:25:35.145053
743 794,3,demo,159,group/Test-for-code-review,"",user_commented_revision:2305443e5a06a9d80e328741d2da742145f80eee,2012-08-30 18:25:55.638486
744 795,3,demo,159,group/Test-for-code-review,"",user_commented_revision:2305443e5a06a9d80e328741d2da742145f80eee,2012-08-30 18:26:45.22087
745 796,3,demo,159,group/Test-for-code-review,"",user_updated_repo,2012-08-30 18:28:52.430153
746 797,3,demo,159,group/Test-for-code-review,"",user_updated_repo,2012-08-30 18:28:59.540779
747 798,3,demo,159,group/Test-for-code-review,"",user_updated_repo,2012-08-30 18:46:21.757499
748 799,3,demo,159,group/Test-for-code-review,"",push_local:1ea6c5155c207b823306f6d4135975cd62de5ea6,2012-08-30 19:06:37.805225
749 800,3,demo,159,group/Test-for-code-review,"",user_commented_revision:1ea6c5155c207b823306f6d4135975cd62de5ea6,2012-08-30 19:07:57.905038
750 801,1,default,159,group/Test-for-code-review,176.9.28.203,pull,2012-08-30 19:12:18.946031
751 802,3,demo,160,group/test-der-zweite,"",started_following_repo,2012-08-30 19:12:19.100001
752 803,3,demo,160,group/test-der-zweite,"",user_created_repo,2012-08-30 19:12:19.109789
753 804,3,demo,160,group/test-der-zweite,"",user_commented_revision:1ea6c5155c207b823306f6d4135975cd62de5ea6,2012-08-30 19:12:33.306323
754 805,3,demo,159,group/Test-for-code-review,"",user_commented_revision:1ea6c5155c207b823306f6d4135975cd62de5ea6,2012-08-30 19:14:51.326684
755 806,3,demo,159,group/Test-for-code-review,"",user_commented_revision:1ea6c5155c207b823306f6d4135975cd62de5ea6,2012-08-30 19:14:54.354662
756 807,3,demo,159,group/Test-for-code-review,"",user_commented_revision:2305443e5a06a9d80e328741d2da742145f80eee,2012-08-30 19:15:23.722829
757 808,150,dlamotte,1,test,"",user_commented_pull_request:31,2012-08-30 23:03:25.180892
758 809,150,dlamotte,1,test,"",user_closed_pull_request:31,2012-08-30 23:03:25.192118
759 810,150,dlamotte,161,test-rhodecode-pull-request,"",started_following_repo,2012-08-30 23:05:08.817245
760 811,150,dlamotte,161,test-rhodecode-pull-request,"",user_created_repo,2012-08-30 23:05:08.832769
761 812,150,dlamotte,161,test-rhodecode-pull-request,143.127.128.10,push:e839aac4f06bb1f0dde813d6b7e80cc345f8d70d,2012-08-30 23:06:12.300969
762 813,150,dlamotte,161,test-rhodecode-pull-request,143.127.128.10,"push:1b01a9f3ba4951615f1c9cfbe19ea62f3abeed9f,062ab363eaef7fc73342a93f4624030103fc36f9",2012-08-30 23:08:29.621962
763 814,1,default,1,test,176.9.28.203,pull,2012-08-30 23:14:51.336754
764 815,151,mill1359,162,test-m,"",started_following_repo,2012-08-30 23:14:51.499881
765 816,151,mill1359,162,test-m,"",user_created_repo,2012-08-30 23:14:51.509169
766 817,1,default,162,test-m,143.127.128.10,pull,2012-08-30 23:16:00.219245
767 818,151,mill1359,162,test-m,143.127.128.10,push:8a528cebe032d5502c73608281a954233347ce36,2012-08-30 23:19:20.205642
768 819,151,mill1359,162,test-m,"",user_commented_pull_request:32,2012-08-30 23:21:27.6093
769 820,151,mill1359,162,test-m,"",user_closed_pull_request:32,2012-08-30 23:21:27.617668
770 821,155,cdugz,163,nagios,"",started_following_repo,2012-08-31 16:42:33.825148
771 822,155,cdugz,163,nagios,"",user_created_repo,2012-08-31 16:42:33.83886
772 895,3,demo,122,amab,"",push_local:f0509a4f718f5a31eafcb8fbe9caf21a642c5753,2012-09-05 01:30:02.737976
773 896,3,demo,32,big-project,"",user_commented_revision:06d5302c4830e5af52f06c462f11f75107b2a1ff,2012-09-05 11:05:19.904842
774 823,155,cdugz,163,nagios,82.150.248.28,"push:380d5c3fd6c3948d5da3f56859104f4adf629553,30b5773f0f9d57cfb721576169685b36878969d1,47deef50eface398daa8ba09a6d79a9db2585c4f,a38d5508f516f360cd603a72cd4a4f16facf5825,cf7656e6c2cb29241db1f6ae0af2823684d7d0b4,0ebf06f94b584abe59853618ca68b9416f13fe20,413886edff138d8de1e3e23698fabba444de6167,335bb28b7c5428044f17ef9bc57a992b759b2d93,feba8837f9ac8af56b6588e8fcc7710eeeebd327,bf0781be32a59aef35f8bf95a2f614894e773926,fc3792349c770fe014d0774e980e3bba600bb5a6",2012-08-31 16:46:05.896127
775 824,155,cdugz,164,rhodecode-ref,"",started_following_repo,2012-08-31 17:42:24.794235
776 825,155,cdugz,164,rhodecode-ref,"",user_created_repo,2012-08-31 17:42:24.806839
777 826,155,cdugz,164,rhodecode-ref,82.150.248.28,"push:380d5c3fd6c3948d5da3f56859104f4adf629553,30b5773f0f9d57cfb721576169685b36878969d1,47deef50eface398daa8ba09a6d79a9db2585c4f,c91bea8206218cf051c6b0ab6a352c7371b5212d",2012-08-31 17:43:03.365708
778 827,155,cdugz,164,rhodecode-ref,"",user_updated_repo,2012-08-31 17:44:01.673127
779 828,155,cdugz,165,rhodecode-dev,"",started_following_repo,2012-08-31 17:44:52.870468
780 829,155,cdugz,165,rhodecode-dev,"",user_created_repo,2012-08-31 17:44:52.880649
781 830,155,cdugz,165,rhodecode-dev,82.150.248.28,"push:380d5c3fd6c3948d5da3f56859104f4adf629553,30b5773f0f9d57cfb721576169685b36878969d1,47deef50eface398daa8ba09a6d79a9db2585c4f,107236f51ef01fcb27d1c613c18a93a2135c336c,2ff774f5163960e356530826b4faad804bd79972,e4b37340f046c2910a43017d814841df1caec1cf,c91bea8206218cf051c6b0ab6a352c7371b5212d,3e5071670c8eec699744bd94f9ebacba8ef33b1f,06303e4e0da2b0e909d985844fc573e3a32547a2",2012-08-31 17:45:20.027085
782 831,3,demo,93,fork-a,"",push_local:416552904882d8b8f051cad2071f4aa271d4ea4e,2012-08-31 18:50:50.885869
783 832,3,demo,166,dfgdfg,"",started_following_repo,2012-08-31 18:56:16.94572
784 833,3,demo,166,dfgdfg,"",user_created_repo,2012-08-31 18:56:16.959102
785 834,3,demo,166,dfgdfg,"",user_updated_repo,2012-08-31 18:56:40.349443
786 835,3,demo,166,dfgdfg,"",user_updated_repo,2012-08-31 18:56:43.138614
787 836,3,demo,167,group/test1234,"",started_following_repo,2012-09-01 13:16:21.279844
788 837,3,demo,167,group/test1234,"",user_created_repo,2012-09-01 13:16:21.293767
789 838,3,demo,168,group/test_interface,"",started_following_repo,2012-09-01 16:31:43.486262
790 839,3,demo,168,group/test_interface,"",user_created_repo,2012-09-01 16:31:43.500171
791 840,3,demo,169,group/demo_interface,"",started_following_repo,2012-09-01 16:33:21.416702
792 841,3,demo,169,group/demo_interface,"",user_created_repo,2012-09-01 16:33:21.429822
793 842,3,demo,169,group/demo_interface,"",user_updated_repo,2012-09-01 16:34:48.888958
794 843,2,admin,,"","",admin_updated_user:demo,2012-09-01 21:37:36.22824
795 844,2,admin,42,foo,"",admin_updated_repo,2012-09-01 21:38:55.72173
796 845,3,demo,68,aaa-project,"",user_commented_revision:2babd97db425482a53b679956df09f89c3154a2c,2012-09-02 02:19:55.864414
797 846,3,demo,68,aaa-project,"",user_commented_revision:2babd97db425482a53b679956df09f89c3154a2c,2012-09-02 02:22:04.179327
798 847,3,demo,68,aaa-project,"",user_commented_revision:2babd97db425482a53b679956df09f89c3154a2c,2012-09-02 02:22:20.301017
799 848,167,asegarra,124,fork-another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-09-03 00:00:02.708105
800 849,167,asegarra,124,fork-another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-09-03 00:00:15.395196
801 850,3,demo,34,a,"",user_commented_revision:332932afc11a2c6308d44e75f8b4ac7643093fa7,2012-09-03 04:40:41.834982
802 851,3,demo,34,a,"",user_commented_revision:332932afc11a2c6308d44e75f8b4ac7643093fa7,2012-09-03 07:13:57.839857
803 852,3,demo,34,a,"",user_commented_revision:332932afc11a2c6308d44e75f8b4ac7643093fa7,2012-09-03 07:15:33.483452
804 853,3,demo,34,a,"",user_commented_revision:332932afc11a2c6308d44e75f8b4ac7643093fa7,2012-09-03 07:28:27.434639
805 854,2,admin,,"","",admin_updated_users_group:group,2012-09-03 08:20:10.984426
806 855,2,admin,,"","",admin_updated_users_group:group,2012-09-03 08:20:22.82228
807 856,2,admin,68,aaa-project,"",admin_updated_repo,2012-09-03 08:28:23.441904
808 857,3,demo,170,_01_jdj,"",started_following_repo,2012-09-03 09:52:03.080751
809 858,3,demo,170,_01_jdj,"",user_created_repo,2012-09-03 09:52:03.103369
810 859,3,demo,171,releases/Blabla,"",started_following_repo,2012-09-03 13:45:50.257273
811 860,3,demo,171,releases/Blabla,"",user_created_repo,2012-09-03 13:45:50.271441
812 861,3,demo,171,releases/Blabla,"",stopped_following_repo,2012-09-03 13:46:24.790546
813 862,3,demo,171,releases/Blabla,"",started_following_repo,2012-09-03 13:46:34.42949
814 863,3,demo,171,releases/Blabla,"",stopped_following_repo,2012-09-03 13:46:37.546423
815 864,3,demo,171,releases/Blabla,"",started_following_repo,2012-09-03 13:46:37.766286
816 865,3,demo,171,releases/Blabla,"",stopped_following_repo,2012-09-03 13:46:38.018055
817 866,3,demo,171,releases/Blabla,"",started_following_repo,2012-09-03 13:46:40.717862
818 867,3,demo,171,releases/Blabla,"",stopped_following_repo,2012-09-03 13:46:40.849278
819 868,3,demo,171,releases/Blabla,"",started_following_repo,2012-09-03 13:46:41.061175
820 869,2,admin,172,go,"",started_following_repo,2012-09-03 14:30:41.496854
821 870,2,admin,172,go,"",admin_created_repo,2012-09-03 14:30:41.508885
822 871,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:d5422faf648cc589425cd3b0dbf1f6dbf93036a0,2012-09-04 02:08:20.759339
823 872,3,demo,34,a,"",user_commented_revision:332932afc11a2c6308d44e75f8b4ac7643093fa7,2012-09-04 02:20:58.295369
824 873,3,demo,34,a,"",user_commented_revision:332932afc11a2c6308d44e75f8b4ac7643093fa7,2012-09-04 02:40:16.584952
825 874,3,demo,173,code-review-dev,"",started_following_repo,2012-09-04 13:01:06.110732
826 875,3,demo,173,code-review-dev,"",user_created_repo,2012-09-04 13:01:06.150884
827 876,3,demo,173,code-review-dev,195.238.92.121,push:cb2ea0ebb59413e325470ee63aa83bb84d9d126c,2012-09-04 13:02:03.374983
828 877,3,demo,173,code-review-dev,"",push_local:ae44a27e7e02d679b00bb94c04c2348d2ca88cd6,2012-09-04 13:03:50.249481
829 878,3,demo,173,code-review-dev,"",user_updated_repo,2012-09-04 13:04:13.26806
830 879,3,demo,173,code-review-dev,"",user_updated_repo,2012-09-04 13:04:17.650534
831 880,3,demo,173,code-review-dev,"",user_updated_repo,2012-09-04 13:05:42.76781
832 881,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:d5422faf648cc589425cd3b0dbf1f6dbf93036a0,2012-09-04 15:59:58.584723
833 882,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:d5422faf648cc589425cd3b0dbf1f6dbf93036a0,2012-09-04 16:00:08.318723
834 883,3,demo,174,cruel-test-2,"",started_following_repo,2012-09-04 16:57:50.235592
835 884,3,demo,174,cruel-test-2,"",user_created_repo,2012-09-04 16:57:50.255676
836 885,3,demo,174,cruel-test-2,"",push_local:b396ac3c7f6c18caf55a87abd84847d345732805,2012-09-04 16:58:25.458669
837 886,3,demo,174,cruel-test-2,"",push_local:a5419e86108ea38b872c9cb0880c312d2595c2aa,2012-09-04 16:59:21.3612
838 887,3,demo,174,cruel-test-2,"",user_commented_revision:a5419e86108ea38b872c9cb0880c312d2595c2aa,2012-09-04 17:01:36.969813
839 888,3,demo,33,fork-big-project,"",push_local:51cec0b8c8a0e47d8edc81d5ffb5f77723c5cbf9,2012-09-04 17:07:03.988595
840 889,3,demo,32,big-project,"",user_commented_pull_request:34,2012-09-04 17:09:12.417908
841 890,3,demo,32,big-project,"",user_commented_pull_request:34,2012-09-04 17:10:04.92285
842 891,3,demo,32,big-project,"",user_closed_pull_request:34,2012-09-04 17:10:04.927287
843 892,3,demo,34,a,"",user_updated_repo,2012-09-05 00:47:01.089512
844 893,3,demo,34,a,"",user_updated_repo,2012-09-05 00:47:11.588561
845 894,3,demo,24,fork-Something,"",user_updated_repo,2012-09-05 01:03:09.893608
846 897,1,default,66,pm-test,195.160.233.181,pull,2012-09-05 13:12:04.976374
847 898,3,demo,66,pm-test,195.160.233.181,push:d19c8fc1bfa2d661d4240e8f120f4ecf6267f9fa,2012-09-05 13:12:51.274952
848 899,3,demo,8,Test_Repo,"",user_commented_pull_request:35,2012-09-05 13:14:25.686481
849 900,3,demo,8,Test_Repo,"",user_commented_pull_request:35,2012-09-05 13:14:43.033131
850 901,3,demo,8,Test_Repo,"",user_closed_pull_request:35,2012-09-05 13:14:43.04395
851 902,1,default,8,Test_Repo,195.160.233.181,pull,2012-09-05 13:17:38.089185
852 903,3,demo,8,Test_Repo,195.160.233.181,push:e8ad7b21735b6590c2dd476e7628ba331a1df384,2012-09-05 13:18:07.5396
853 904,3,demo,175,fork-a-one-more,"",started_following_repo,2012-09-05 13:20:22.809301
854 905,3,demo,34,a,"",user_forked_repo:fork-a-one-more,2012-09-05 13:20:22.832688
855 906,3,demo,175,fork-a-one-more,"",user_created_fork:fork-a-one-more,2012-09-05 13:20:22.841274
856 907,3,demo,175,fork-a-one-more,195.160.233.181,pull,2012-09-05 13:20:54.391748
857 908,3,demo,175,fork-a-one-more,195.160.233.181,push:c6fb8c3fe1a8393f8861c39bf590d3865c503ca5,2012-09-05 13:22:36.203898
858 909,3,demo,34,a,"",user_commented_pull_request:36,2012-09-05 13:23:55.420971
859 910,3,demo,34,a,"",user_commented_pull_request:36,2012-09-05 13:24:17.361904
860 911,3,demo,34,a,"",user_commented_pull_request:36,2012-09-05 13:24:35.76659
861 912,3,demo,34,a,"",user_closed_pull_request:36,2012-09-05 13:24:35.7744
862 913,3,demo,34,a,"",user_commented_pull_request:37,2012-09-05 13:30:57.812004
863 914,3,demo,34,a,"",user_commented_pull_request:38,2012-09-05 13:38:45.300458
864 915,3,demo,34,a,"",user_commented_pull_request:38,2012-09-05 13:39:01.382629
865 916,3,demo,34,a,"",user_commented_pull_request:38,2012-09-05 13:39:18.062238
866 917,3,demo,34,a,"",user_commented_pull_request:38,2012-09-05 13:39:27.350966
867 918,3,demo,34,a,"",user_commented_pull_request:38,2012-09-05 13:39:37.275952
868 919,3,demo,34,a,"",user_updated_repo,2012-09-05 13:40:21.966185
869 920,3,demo,34,a,"",user_commented_pull_request:37,2012-09-05 13:40:53.832787
870 921,3,demo,34,a,"",user_closed_pull_request:37,2012-09-05 13:40:53.837264
871 922,3,demo,34,a,"",user_commented_pull_request:38,2012-09-05 13:41:51.071776
872 923,3,demo,34,a,"",user_closed_pull_request:38,2012-09-05 13:41:51.082763
873 924,3,demo,34,a,"",user_updated_repo,2012-09-05 13:42:28.045216
874 925,3,demo,176,hopsa,"",started_following_repo,2012-09-05 14:12:14.479866
875 926,3,demo,165,rhodecode-dev,"",user_forked_repo:hopsa,2012-09-05 14:12:14.495649
876 927,3,demo,176,hopsa,"",user_created_fork:hopsa,2012-09-05 14:12:14.507312
877 928,3,demo,177,blah,"",started_following_repo,2012-09-05 16:42:29.860682
878 929,3,demo,177,blah,"",user_created_repo,2012-09-05 16:42:29.876509
879 930,3,demo,178,myfolder-myrepo,"",started_following_repo,2012-09-05 17:33:08.753339
880 931,3,demo,178,myfolder-myrepo,"",user_created_repo,2012-09-05 17:33:08.765789
881 932,3,demo,180,MineReps,"",started_following_repo,2012-09-05 23:11:25.562383
882 933,3,demo,180,MineReps,"",user_created_repo,2012-09-05 23:11:25.577972
883 934,3,demo,33,fork-big-project,"",user_commented_revision:51cec0b8c8a0e47d8edc81d5ffb5f77723c5cbf9,2012-09-06 01:29:52.749682
884 935,3,demo,33,fork-big-project,"",user_commented_revision:51cec0b8c8a0e47d8edc81d5ffb5f77723c5cbf9,2012-09-06 01:30:05.246986
885 936,1,default,68,aaa-project,94.194.60.137,pull,2012-09-06 02:51:08.186518
886 937,1,default,68,aaa-project,94.194.60.137,pull,2012-09-06 02:54:47.80033
887 938,1,default,159,group/Test-for-code-review,"",push_local:e25e53f9a9cd4a39bb085830a67983bc6dd46e76,2012-09-06 03:08:45.578824
888 939,3,demo,159,group/Test-for-code-review,"",user_commented_revision:e25e53f9a9cd4a39bb085830a67983bc6dd46e76,2012-09-06 03:30:51.35489
889 940,3,demo,68,aaa-project,"",user_updated_repo,2012-09-06 04:44:10.863264
890 941,3,demo,68,aaa-project,"",user_updated_repo,2012-09-06 04:44:41.091954
891 942,3,demo,68,aaa-project,"",push_local:e3fef0be8dc20eb1fa68fc45292d9d66de1cc67f,2012-09-06 04:45:38.572986
892 943,3,demo,68,aaa-project,"",user_commented_revision:e3fef0be8dc20eb1fa68fc45292d9d66de1cc67f,2012-09-06 04:57:07.744368
893 944,3,demo,68,aaa-project,"",push_local:bc829c34912709c7d129e5dae9a3e5ff46e77fc7,2012-09-06 04:57:36.830617
894 945,3,demo,68,aaa-project,"",user_commented_revision:bc829c34912709c7d129e5dae9a3e5ff46e77fc7,2012-09-06 04:58:00.171714
895 946,3,demo,68,aaa-project,"",user_commented_revision:e3fef0be8dc20eb1fa68fc45292d9d66de1cc67f,2012-09-06 05:01:46.10616
896 947,3,demo,68,aaa-project,"",user_updated_repo,2012-09-06 05:03:07.692388
897 948,2,admin,,"","",admin_updated_user:ThunderEagle,2012-09-06 09:36:46.171404
898 949,2,admin,,"","",admin_updated_user:nipocetyueai,2012-09-06 09:36:50.92007
899 950,2,admin,,"","",admin_updated_user:mnemonikk,2012-09-06 09:36:56.872411
900 951,2,admin,,"","",admin_updated_user:kasai,2012-09-06 09:37:01.993148
901 952,2,admin,,"","",admin_updated_user:Gerhard,2012-09-06 09:37:06.197752
902 953,2,admin,,"","",admin_updated_user:dtucker,2012-09-06 09:37:10.301831
903 954,3,demo,181,group/MyTestRepo,"",started_following_repo,2012-09-06 15:19:51.89625
904 955,3,demo,181,group/MyTestRepo,"",user_created_repo,2012-09-06 15:19:51.912381
905 956,182,nohj,93,fork-a,"",user_commented_revision:7f8b4f94e2a83394aa687e0bb110870769e9ca0a,2012-09-07 09:42:56.913732
906 957,182,nohj,93,fork-a,"",user_commented_revision:7f8b4f94e2a83394aa687e0bb110870769e9ca0a,2012-09-07 09:43:06.314091
907 958,3,demo,182,releases/test,"",started_following_repo,2012-09-07 11:22:43.780986
908 959,3,demo,182,releases/test,"",user_created_repo,2012-09-07 11:22:43.795541
909 960,3,demo,183,releases/fork-test,"",started_following_repo,2012-09-07 11:23:52.711668
910 961,3,demo,182,releases/test,"",user_forked_repo:releases/fork-test,2012-09-07 11:23:52.72963
911 962,3,demo,183,releases/fork-test,"",user_created_fork:releases/fork-test,2012-09-07 11:23:52.742467
912 963,3,demo,184,fork-aaa-project,"",started_following_repo,2012-09-07 11:28:35.495082
913 964,3,demo,68,aaa-project,"",user_forked_repo:fork-aaa-project,2012-09-07 11:28:35.510311
914 965,3,demo,184,fork-aaa-project,"",user_created_fork:fork-aaa-project,2012-09-07 11:28:35.523318
915 966,3,demo,184,fork-aaa-project,"",push_local:b25fcd2b8f033115be20d9146c99c1aa6854dff0,2012-09-07 11:29:20.828412
916 967,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-09-07 11:32:38.639523
917 968,3,demo,185,TestRepositoryCS,"",started_following_repo,2012-09-07 13:53:39.687423
918 969,3,demo,185,TestRepositoryCS,"",user_created_repo,2012-09-07 13:53:39.702762
919 970,3,demo,186,releases/softpedia,"",started_following_repo,2012-09-07 14:23:28.805185
920 971,3,demo,186,releases/softpedia,"",user_created_repo,2012-09-07 14:23:28.815298
921 972,3,demo,187,ptest,"",started_following_repo,2012-09-07 20:29:00.365852
922 973,3,demo,187,ptest,"",user_created_repo,2012-09-07 20:29:00.379277
923 974,3,demo,187,ptest,89.72.81.164,push:527819ac5de5c1ef222e10faa94d00031ff92276,2012-09-07 20:35:02.456136
924 975,3,demo,187,ptest,89.72.81.164,push:20312aeb821607689952b2e56de6167927c2790b,2012-09-07 20:40:50.055559
925 976,3,demo,187,ptest,"",user_commented_revision:20312aeb821607689952b2e56de6167927c2790b,2012-09-07 20:43:26.445007
926 977,141,asdf1234asdf,188,fork-Asdf,"",started_following_repo,2012-09-07 21:22:53.452145
927 978,141,asdf1234asdf,135,Asdf,"",user_forked_repo:fork-Asdf,2012-09-07 21:22:53.472411
928 979,141,asdf1234asdf,188,fork-Asdf,"",user_created_fork:fork-Asdf,2012-09-07 21:22:53.485295
929 980,141,asdf1234asdf,188,fork-Asdf,"",push_local:cf7c116b1345f1aa0b1df0d1c36abce396082561,2012-09-07 21:23:31.404039
930 981,141,asdf1234asdf,135,Asdf,"",user_commented_pull_request:40,2012-09-07 21:24:53.455489
931 982,141,asdf1234asdf,135,Asdf,"",user_closed_pull_request:40,2012-09-07 21:24:53.467808
932 983,3,demo,68,aaa-project,"",user_commented_revision:bc829c34912709c7d129e5dae9a3e5ff46e77fc7,2012-09-07 22:54:29.053992
933 984,3,demo,189,fork-_01_jdj,"",started_following_repo,2012-09-07 22:55:46.169783
934 985,3,demo,170,_01_jdj,"",user_forked_repo:fork-_01_jdj,2012-09-07 22:55:46.191342
935 986,3,demo,189,fork-_01_jdj,"",user_created_fork:fork-_01_jdj,2012-09-07 22:55:46.209143
936 987,2,admin,190,rhodecode,"",started_following_repo,2012-09-08 01:07:09.881091
937 988,2,admin,190,rhodecode,"",admin_created_repo,2012-09-08 01:07:09.895097
938 989,3,demo,34,a,"",user_commented_revision:332932afc11a2c6308d44e75f8b4ac7643093fa7,2012-09-08 08:57:27.586796
939 990,3,demo,191,kekeke,"",started_following_repo,2012-09-08 11:22:58.159504
940 991,3,demo,191,kekeke,"",user_created_repo,2012-09-08 11:22:58.175212
941 992,3,demo,191,kekeke,"",push_local:40926265e8964e7b71381c9c9e1d3c4dbdd158cc,2012-09-08 11:23:11.019021
942 993,3,demo,191,kekeke,"",user_commented_revision:40926265e8964e7b71381c9c9e1d3c4dbdd158cc,2012-09-08 11:23:26.28488
943 994,3,demo,192,fork-kekeke,"",started_following_repo,2012-09-08 11:23:53.101414
944 995,3,demo,191,kekeke,"",user_forked_repo:fork-kekeke,2012-09-08 11:23:53.115395
945 996,3,demo,192,fork-kekeke,"",user_created_fork:fork-kekeke,2012-09-08 11:23:53.129381
946 997,3,demo,192,fork-kekeke,"",push_local:f6c6170cb0cd27fd21d4a8f4ae477bb86ee67e6e,2012-09-08 11:24:25.629176
947 998,3,demo,192,fork-kekeke,"",user_commented_revision:f6c6170cb0cd27fd21d4a8f4ae477bb86ee67e6e,2012-09-08 11:24:36.698761
948 999,3,demo,192,fork-kekeke,"",user_commented_revision:f6c6170cb0cd27fd21d4a8f4ae477bb86ee67e6e,2012-09-08 11:26:01.605011
949 1000,3,demo,193,swamp,"",started_following_repo,2012-09-08 11:27:28.069118
950 1001,3,demo,193,swamp,"",user_created_repo,2012-09-08 11:27:28.079797
951 1002,3,demo,193,swamp,"",push_local:c4cd716a477bd604e57f8a07c28462f2e55b1282,2012-09-08 11:27:40.680692
952 1003,3,demo,194,fork-swamp,"",started_following_repo,2012-09-08 11:28:05.141092
953 1004,3,demo,193,swamp,"",user_forked_repo:fork-swamp,2012-09-08 11:28:05.223876
954 1005,3,demo,194,fork-swamp,"",user_created_fork:fork-swamp,2012-09-08 11:28:05.233149
955 1006,3,demo,194,fork-swamp,"",push_local:cdf8380186a792bffb9be284df1bd95c631143ca,2012-09-08 11:28:33.802256
956 1007,3,demo,193,swamp,"",user_commented_pull_request:41,2012-09-08 11:29:22.818392
957 1008,3,demo,193,swamp,"",user_closed_pull_request:41,2012-09-08 11:29:22.824771
958 1009,3,demo,193,swamp,"",user_updated_repo,2012-09-08 11:32:58.174439
959 1010,3,demo,,group/book,"",started_following_repo,2012-09-08 18:59:38.392464
960 1011,3,demo,,group/book,"",user_created_repo,2012-09-08 18:59:38.412482
961 1012,3,demo,,group/book,"",push_local:da7ffa14ae51096c974b2297cfd8a10009b44266,2012-09-08 19:01:38.20195
962 1013,3,demo,,group/book,"",stopped_following_repo,2012-09-08 19:04:50.017367
963 1014,3,demo,,group/book,"",user_deleted_repo,2012-09-08 19:09:36.059085
964 1015,183,dotnet,196,PD,"",started_following_repo,2012-09-08 22:57:37.558354
965 1016,183,dotnet,196,PD,"",user_created_repo,2012-09-08 22:57:37.570947
966 1017,183,dotnet,196,group/PD,"",user_updated_repo,2012-09-08 22:58:13.674462
967 1018,3,demo,197,CollectionQuery,"",started_following_repo,2012-09-09 00:58:29.372736
968 1019,3,demo,197,CollectionQuery,"",user_created_repo,2012-09-09 00:58:29.391956
969 1020,3,demo,197,CollectionQuery,"",user_commented_revision:34f0cefd8f7fbddf412daddc8676483f71456e8d,2012-09-09 00:58:51.17291
970 1021,3,demo,197,CollectionQuery,"",user_commented_revision:34f0cefd8f7fbddf412daddc8676483f71456e8d,2012-09-09 00:58:56.364677
971 1022,3,demo,198,fork-CollectionQuery,"",started_following_repo,2012-09-09 00:59:36.116229
972 1023,3,demo,197,CollectionQuery,"",user_forked_repo:fork-CollectionQuery,2012-09-09 00:59:36.133811
973 1024,3,demo,198,fork-CollectionQuery,"",user_created_fork:fork-CollectionQuery,2012-09-09 00:59:36.214126
974 1025,3,demo,199,fork-fork-CollectionQuery,"",started_following_repo,2012-09-09 00:59:57.408192
975 1026,3,demo,198,fork-CollectionQuery,"",user_forked_repo:fork-fork-CollectionQuery,2012-09-09 00:59:57.423968
976 1027,3,demo,199,fork-fork-CollectionQuery,"",user_created_fork:fork-fork-CollectionQuery,2012-09-09 00:59:57.433065
977 1028,3,demo,199,fork-fork-CollectionQuery,195.43.146.59,push:69ce02e460b36f4c28a468ac1356b579b9a954ff,2012-09-09 01:01:22.306272
978 1029,3,demo,198,fork-CollectionQuery,"",user_commented_pull_request:42,2012-09-09 01:02:19.007376
979 1030,3,demo,198,fork-CollectionQuery,"",user_commented_pull_request:42,2012-09-09 01:02:27.274382
980 1031,3,demo,198,fork-CollectionQuery,"",user_commented_pull_request:42,2012-09-09 01:02:58.084638
981 1032,3,demo,198,fork-CollectionQuery,"",user_commented_pull_request:42,2012-09-09 01:03:24.236666
982 1033,3,demo,198,fork-CollectionQuery,"",user_closed_pull_request:42,2012-09-09 01:03:24.242005
983 1034,3,demo,199,fork-fork-CollectionQuery,"",user_updated_repo,2012-09-09 01:07:10.157164
984 1035,3,demo,200,group/MostafaTest,"",started_following_repo,2012-09-09 05:40:58.979338
985 1036,3,demo,200,group/MostafaTest,"",user_created_repo,2012-09-09 05:40:58.990523
986 1037,3,demo,200,group/MostafaTest,"",user_updated_repo,2012-09-09 05:41:48.334746
987 1055,184,testar,201,tord,"",user_commented_pull_request:44,2012-09-09 19:54:21.605064
988 1056,184,testar,201,tord,"",user_closed_pull_request:44,2012-09-09 19:54:21.613226
989 1039,3,demo,170,_01_jdj,"",user_updated_repo,2012-09-09 07:53:52.339713
990 1040,3,demo,170,_01_jdj,"",user_updated_repo,2012-09-09 07:54:26.72259
991 1041,3,demo,170,group/_01_jdj,"",user_updated_repo,2012-09-09 07:55:38.58919
992 1042,184,testar,201,tord,"",started_following_repo,2012-09-09 18:14:16.86889
993 1043,184,testar,201,tord,"",user_created_repo,2012-09-09 18:14:16.882512
994 1044,184,testar,163,nagios,"",started_following_repo,2012-09-09 18:15:38.62944
995 1045,184,testar,201,tord,"",push_local:35b3ebc8e1c23902eb97031f42f666df0835c5be,2012-09-09 18:19:47.818844
996 1046,184,testar,202,fork-tord,"",started_following_repo,2012-09-09 18:20:57.856478
997 1047,184,testar,201,tord,"",user_forked_repo:fork-tord,2012-09-09 18:20:57.874063
998 1048,184,testar,202,fork-tord,"",user_created_fork:fork-tord,2012-09-09 18:20:57.882599
999 1049,184,testar,202,fork-tord,"",push_local:9a2c544511d0a4acd495e8ea5731a8991a74282e,2012-09-09 18:21:38.707225
1000 1050,184,testar,201,tord,"",user_commented_pull_request:43,2012-09-09 18:25:50.104238
1001 1051,184,testar,201,tord,"",user_closed_pull_request:43,2012-09-09 18:25:50.113446
1002 1052,184,testar,201,tord,"",user_commented_pull_request:44,2012-09-09 18:27:24.712191
1003 1053,184,testar,201,tord,"",user_commented_pull_request:44,2012-09-09 18:28:22.083687
1004 1054,184,testar,201,tord,"",user_updated_repo,2012-09-09 18:29:15.858734
1005 1057,185,robert.zaremba,90,a-fork1,"",user_commented_revision:b09d43f798414bcbdf4dc1fc5dafe6ce4aa5afc3,2012-09-09 22:27:16.614006
1006 1058,185,robert.zaremba,90,a-fork1,"",user_commented_revision:7672806f881f67eb1441d00b16e983e761127cb6,2012-09-09 22:32:41.43306
1007 1059,185,robert.zaremba,90,a-fork1,"",user_commented_revision:7672806f881f67eb1441d00b16e983e761127cb6,2012-09-09 22:33:13.181212
1008 1060,3,demo,203,testtt,"",started_following_repo,2012-09-10 09:06:26.895244
1009 1061,3,demo,203,testtt,"",user_created_repo,2012-09-10 09:06:26.906878
1010 1062,3,demo,34,a,"",user_commented_revision:7672806f881f67eb1441d00b16e983e761127cb6,2012-09-10 10:05:40.492293
1011 1063,3,demo,68,aaa-project,"",user_commented_revision:bc829c34912709c7d129e5dae9a3e5ff46e77fc7,2012-09-10 18:01:16.277098
1012 1064,3,demo,81,FS_dummy,"",user_updated_repo,2012-09-10 18:06:21.324052
1013 1065,3,demo,204,releases/Sopra_testgd,"",started_following_repo,2012-09-10 18:11:02.020678
1014 1066,3,demo,204,releases/Sopra_testgd,"",user_created_repo,2012-09-10 18:11:02.030205
1015 1067,3,demo,204,releases/Sopra_testgd,"",push_local:284745170ffd9e889c2edfb0233b6d654e787fa9,2012-09-10 18:12:24.966918
1016 1068,3,demo,204,releases/Sopra_testgd,"",user_commented_revision:284745170ffd9e889c2edfb0233b6d654e787fa9,2012-09-10 18:14:01.969763
1017 1069,3,demo,205,releases/fork-Sopra_testgd,"",started_following_repo,2012-09-10 18:16:19.48076
1018 1070,3,demo,204,releases/Sopra_testgd,"",user_forked_repo:releases/fork-Sopra_testgd,2012-09-10 18:16:19.499335
1019 1071,3,demo,205,releases/fork-Sopra_testgd,"",user_created_fork:releases/fork-Sopra_testgd,2012-09-10 18:16:19.511534
1020 1072,3,demo,205,releases/fork-Sopra_testgd,"",push_local:99095f2d5703cbc43294ef55a19c5cc9e4cc2c15,2012-09-10 18:21:23.60213
1021 1073,189,bondsbw,57,SuperProject,"",user_commented_revision:a3188ce9ed64822ceae497665910c2e18cddf021,2012-09-10 22:54:09.907623
1022 1074,189,bondsbw,122,amab,"",user_commented_revision:f0509a4f718f5a31eafcb8fbe9caf21a642c5753,2012-09-10 22:55:47.862221
1023 1075,108,dukeofgaming,124,fork-another-fork-to-check-code-review,"",push_local:a48ce47517381c8ca647c5f5ed459cfd16c2d929,2012-09-11 19:49:34.961449
1024 1076,3,demo,206,test-sls,"",started_following_repo,2012-09-11 22:38:29.066354
1025 1077,3,demo,206,test-sls,"",user_created_repo,2012-09-11 22:38:29.079212
1026 1078,3,demo,206,test-sls,"",push_local:dd00a017d1957479cfcde1e452b625de41dde9d2,2012-09-11 22:38:53.239821
1027 1079,3,demo,207,fork-test-sls,"",started_following_repo,2012-09-11 22:39:50.010568
1028 1080,3,demo,206,test-sls,"",user_forked_repo:fork-test-sls,2012-09-11 22:39:50.029999
1029 1081,3,demo,207,fork-test-sls,"",user_created_fork:fork-test-sls,2012-09-11 22:39:50.043157
1030 1082,3,demo,206,test-sls,"",push_local:c6b89acf0f7cd0b524001d0aa6f5ab3b83c30610,2012-09-11 22:40:31.203174
1031 1083,3,demo,54,glib,"",user_commented_revision:538b2f106de78b7dfeac2a98f3d5594ed0ed2ade,2012-09-12 00:11:20.855342
1032 1084,3,demo,54,glib,"",user_commented_revision:82d914d808c616d14d489c0272c6d5afc4bfbd5a,2012-09-12 00:12:22.85722
1033 1085,3,demo,208,fork-foo-test-pull-request,"",started_following_repo,2012-09-12 05:01:27.90602
1034 1086,3,demo,42,foo,"",user_forked_repo:fork-foo-test-pull-request,2012-09-12 05:01:30.440339
1035 1087,3,demo,208,fork-foo-test-pull-request,"",user_created_fork:fork-foo-test-pull-request,2012-09-12 05:01:30.452552
1036 1088,3,demo,208,fork-foo-test-pull-request,"",push_local:466e27f74322722e315290532fbcb304f6d58c89,2012-09-12 05:03:04.911355
1037 1089,3,demo,209,simple,"",started_following_repo,2012-09-12 05:06:08.645688
1038 1090,3,demo,209,simple,"",user_created_repo,2012-09-12 05:06:08.657642
1039 1091,3,demo,209,simple,"",push_local:f486184ddd95d91608069a8551febd72e268f4df,2012-09-12 05:07:25.821515
1040 1092,3,demo,210,simple-dev,"",started_following_repo,2012-09-12 05:08:21.036466
1041 1093,3,demo,209,simple,"",user_forked_repo:simple-dev,2012-09-12 05:08:21.055166
1042 1094,3,demo,210,simple-dev,"",user_created_fork:simple-dev,2012-09-12 05:08:21.069551
1043 1095,3,demo,210,simple-dev,"",push_local:5041fad58a9214bf203d139c171a277c51bac1a3,2012-09-12 05:09:16.139893
1044 1096,3,demo,209,simple,"",user_commented_pull_request:47,2012-09-12 05:11:57.925581
1045 1097,3,demo,209,simple,"",user_commented_pull_request:47,2012-09-12 05:12:24.949869
1046 1098,3,demo,209,simple,"",user_closed_pull_request:47,2012-09-12 05:12:24.958144
1047 1099,1,default,209,simple,221.237.152.62,pull,2012-09-12 05:40:02.318983
1048 1100,1,default,210,simple-dev,221.237.152.62,pull,2012-09-12 05:40:17.924834
1049 1101,1,default,210,simple-dev,221.237.152.62,pull,2012-09-12 05:40:49.20005
1050 1102,3,demo,209,simple,221.237.152.62,push:5041fad58a9214bf203d139c171a277c51bac1a3,2012-09-12 05:41:15.014744
1051 1103,3,demo,210,simple-dev,"",push_local:bbcf483fdda92478ca6a00a0f14cc77815d5414f,2012-09-12 05:47:24.31048
1052 1104,3,demo,210,simple-dev,"",user_updated_repo,2012-09-12 05:48:00.607586
1053 1105,3,demo,209,simple,"",user_commented_pull_request:48,2012-09-12 05:49:58.582042
1054 1106,3,demo,209,simple,"",user_closed_pull_request:48,2012-09-12 05:49:58.589388
1055 1107,1,default,210,simple-dev,221.237.152.62,pull,2012-09-12 05:50:50.549103
1056 1108,3,demo,209,simple,221.237.152.62,push:bbcf483fdda92478ca6a00a0f14cc77815d5414f,2012-09-12 05:51:17.124232
1057 1109,3,demo,34,a,"",push_local:48e1ba33b7951b8e8023e3e3cc54ef2540f4e8f1,2012-09-12 08:36:56.839135
1058 1110,3,demo,120,group/clojure.git,"",user_updated_repo,2012-09-12 10:03:47.644822
1059 1111,3,demo,174,cruel-test-2,"",push_local:a0971ac6b506a17718c1544689f3f6cfc261576d,2012-09-12 10:54:25.099359
1060 1112,3,demo,174,releases/cruel-test-2,"",user_updated_repo,2012-09-12 10:55:26.86657
1061 1113,3,demo,174,releases/cruel-test-2,"",user_updated_repo,2012-09-12 10:55:30.573836
1062 1114,2,admin,211,testΓ©1,"",started_following_repo,2012-09-12 11:57:41.047778
1063 1115,2,admin,211,testΓ©1,"",admin_created_repo,2012-09-12 11:57:41.083287
1064 1116,3,demo,169,group/demo_interface,"",user_updated_repo,2012-09-12 12:07:54.077355
1065 1117,3,demo,174,releases/cruel-test-2,"",stopped_following_repo,2012-09-12 12:08:52.082216
1066 1118,3,demo,174,releases/cruel-test-2,"",started_following_repo,2012-09-12 12:08:53.730447
1067 1119,3,demo,174,releases/cruel-test-2,"",stopped_following_repo,2012-09-12 12:08:55.148237
1068 1120,3,demo,209,simple,"",user_commented_revision:bbcf483fdda92478ca6a00a0f14cc77815d5414f,2012-09-12 12:12:45.729356
1069 1121,3,demo,209,simple,"",user_commented_revision:5041fad58a9214bf203d139c171a277c51bac1a3,2012-09-12 12:14:55.164695
1070 1122,193,test1234124890814,212,group/fork-aaa-project,"",started_following_repo,2012-09-12 21:55:02.137169
1071 1123,193,test1234124890814,68,aaa-project,"",user_forked_repo:group/fork-aaa-project,2012-09-12 21:55:02.184564
1072 1124,193,test1234124890814,212,group/fork-aaa-project,"",user_created_fork:group/fork-aaa-project,2012-09-12 21:55:02.198242
1073 1125,3,demo,36,bootstrap,"",user_updated_repo,2012-09-13 11:40:44.539269
1074 1126,3,demo,36,bootstrap,"",user_updated_repo,2012-09-13 11:40:50.053297
1075 1127,3,demo,34,a,"",user_commented_revision:48e1ba33b7951b8e8023e3e3cc54ef2540f4e8f1,2012-09-13 11:45:58.772773
1076 1128,3,demo,213,fork-aii,"",started_following_repo,2012-09-13 11:47:05.531304
1077 1129,3,demo,34,a,"",user_forked_repo:fork-aii,2012-09-13 11:47:05.549251
1078 1130,3,demo,213,fork-aii,"",user_created_fork:fork-aii,2012-09-13 11:47:05.56141
1079 1131,3,demo,214,group/fork-clojure.git2,"",started_following_repo,2012-09-13 11:49:07.655132
1080 1132,3,demo,120,group/clojure.git,"",user_forked_repo:group/fork-clojure.git2,2012-09-13 11:49:09.06382
1081 1133,3,demo,214,group/fork-clojure.git2,"",user_created_fork:group/fork-clojure.git2,2012-09-13 11:49:09.078581
1082 1134,3,demo,34,a,"",push_local:f437e821a406d35b1e231c5a81e82853f8ed6436,2012-09-13 11:54:41.606977
1083 1135,3,demo,34,a,"",user_commented_revision:f437e821a406d35b1e231c5a81e82853f8ed6436,2012-09-13 11:54:58.759518
1084 1136,3,demo,215,fork-aaa-project-fork,"",started_following_repo,2012-09-13 13:38:46.509316
1085 1137,3,demo,68,aaa-project,"",user_forked_repo:fork-aaa-project-fork,2012-09-13 13:38:46.527575
1086 1138,3,demo,215,fork-aaa-project-fork,"",user_created_fork:fork-aaa-project-fork,2012-09-13 13:38:46.539228
1087 1139,3,demo,215,fork-aaa-project-fork,"",push_local:7a8d3ab1f8ae1f1ab29a8b91b1946d92e30d46b3,2012-09-13 13:39:43.069005
1088 1140,3,demo,68,aaa-project,"",stopped_following_repo,2012-09-13 15:29:12.016889
1089 1141,3,demo,68,aaa-project,"",started_following_repo,2012-09-13 15:29:12.692509
1090 1142,195,emcconne,216,TestingRhino,"",started_following_repo,2012-09-13 17:30:27.876656
1091 1143,195,emcconne,216,TestingRhino,"",user_created_repo,2012-09-13 17:30:27.892609
1092 1144,198,sdfsdf,217,sdfsdf,"",started_following_repo,2012-09-14 08:58:28.936153
1093 1145,198,sdfsdf,217,sdfsdf,"",user_created_repo,2012-09-14 08:58:28.945587
1094 1146,198,sdfsdf,217,sdfsdf,"",push_local:13d78aa20a388de51a7717800e6d3ce5d186bb19,2012-09-14 08:58:39.080817
1095 1147,3,demo,218,TestRepo,"",started_following_repo,2012-09-14 11:07:12.582488
1096 1148,3,demo,218,TestRepo,"",user_created_repo,2012-09-14 11:07:12.591173
1097 1149,3,demo,68,aaa-project,"",user_commented_pull_request:50,2012-09-14 13:24:16.044125
1098 1150,3,demo,68,aaa-project,"",user_commented_pull_request:50,2012-09-14 13:24:51.197813
1099 1151,3,demo,68,aaa-project,"",user_closed_pull_request:50,2012-09-14 13:24:51.217266
1100 1152,3,demo,68,aaa-project,"",user_updated_repo,2012-09-14 13:27:23.206802
1101 1153,3,demo,34,a,"",user_commented_revision:f437e821a406d35b1e231c5a81e82853f8ed6436,2012-09-14 16:02:30.704441
1102 1154,200,animusoft,219,Animusoft.Respository,"",started_following_repo,2012-09-14 18:02:30.536279
1103 1155,200,animusoft,219,Animusoft.Respository,"",user_created_repo,2012-09-14 18:02:30.545377
1104 1156,200,animusoft,219,Animusoft.Respository,"",push_local:73da86adad8bdb1ce83aa6a5d0c603a9b28b4a37,2012-09-14 18:04:26.459249
1105 1157,200,animusoft,219,Animusoft.Respository,"",push_local:6b8fe7f9d13089ca20dddca163b35f7d8651f60f,2012-09-14 18:05:16.811723
1106 1158,201,AsyA,220,TestTestTestTestTestTest,"",started_following_repo,2012-09-14 19:16:17.886851
1107 1159,201,AsyA,220,TestTestTestTestTestTest,"",user_created_repo,2012-09-14 19:16:17.895972
1108 1160,201,AsyA,220,TestTestTestTestTestTest,"",push_local:25acf78d91b645e98173440645ccfe14688b1f20,2012-09-14 19:17:19.578893
1109 1161,201,AsyA,220,TestTestTestTestTestTest,"",push_local:f067475760e5739e2c9ada32160ff4d14193071b,2012-09-14 19:20:09.018005
1110 1162,201,AsyA,220,TestTestTestTestTestTest,"",user_commented_revision:f067475760e5739e2c9ada32160ff4d14193071b,2012-09-14 19:20:26.225849
1111 1163,201,AsyA,220,TestTestTestTestTestTest,"",user_commented_revision:f067475760e5739e2c9ada32160ff4d14193071b,2012-09-14 19:20:31.314463
1112 1164,201,AsyA,220,TestTestTestTestTestTest,"",user_commented_revision:f067475760e5739e2c9ada32160ff4d14193071b,2012-09-14 19:20:36.071029
1113 1165,201,AsyA,220,TestTestTestTestTestTest,"",user_commented_revision:f067475760e5739e2c9ada32160ff4d14193071b,2012-09-14 19:20:42.675126
1114 1166,201,AsyA,220,TestTestTestTestTestTest,"",user_commented_revision:f067475760e5739e2c9ada32160ff4d14193071b,2012-09-14 19:20:45.57336
1115 1167,201,AsyA,220,TestTestTestTestTestTest,"",user_commented_revision:f067475760e5739e2c9ada32160ff4d14193071b,2012-09-14 19:20:48.976628
1116 1168,201,AsyA,221,fork-TestTestTestTestTestTest,"",started_following_repo,2012-09-14 19:26:54.224113
1117 1169,201,AsyA,220,TestTestTestTestTestTest,"",user_forked_repo:fork-TestTestTestTestTestTest,2012-09-14 19:26:54.236074
1118 1170,201,AsyA,221,fork-TestTestTestTestTestTest,"",user_created_fork:fork-TestTestTestTestTestTest,2012-09-14 19:26:54.243559
1119 1171,201,AsyA,221,fork-TestTestTestTestTestTest,"",push_local:05e54fdd720c30f564ed12bdbff6dbbeb55f3816,2012-09-14 19:29:39.084466
1120 1172,201,AsyA,220,TestTestTestTestTestTest,"",user_commented_pull_request:51,2012-09-14 19:36:31.399955
1121 1173,201,AsyA,220,TestTestTestTestTestTest,"",user_closed_pull_request:51,2012-09-14 19:36:31.404011
1122 1174,201,AsyA,220,TestTestTestTestTestTest,"",push_local:79f5d792cff0085cf103a76c7a19934de3828f43,2012-09-14 19:44:41.485916
1123 1175,203,f.ludwig,222,florian-test,"",started_following_repo,2012-09-15 14:46:45.248996
1124 1176,203,f.ludwig,222,florian-test,"",user_created_repo,2012-09-15 14:46:45.258481
1125 1177,203,f.ludwig,223,florian-test-fork,"",started_following_repo,2012-09-15 14:47:01.375283
1126 1178,203,f.ludwig,222,florian-test,"",user_forked_repo:florian-test-fork,2012-09-15 14:47:01.40721
1127 1179,203,f.ludwig,223,florian-test-fork,"",user_created_fork:florian-test-fork,2012-09-15 14:47:01.415249
1128 1180,203,f.ludwig,223,florian-test-fork,"",push_local:028186940dbf5db5818c2c0a9ff80f214da0fd3f,2012-09-15 15:20:01.863826
1129 1181,203,f.ludwig,223,florian-test-fork,"",push_local:4225a7038b6d6bb193056967830ba56a2f38b005,2012-09-15 15:20:28.233187
1130 1182,203,f.ludwig,223,florian-test-fork,"",user_commented_revision:4225a7038b6d6bb193056967830ba56a2f38b005,2012-09-15 15:20:38.339449
1131 1183,203,f.ludwig,223,florian-test-fork,"",user_commented_revision:4225a7038b6d6bb193056967830ba56a2f38b005,2012-09-15 15:20:43.785366
1132 1184,203,f.ludwig,223,florian-test-fork,"",user_commented_revision:4225a7038b6d6bb193056967830ba56a2f38b005,2012-09-15 15:21:21.2331
1133 1185,193,test1234124890814,224,gnomon,"",started_following_repo,2012-09-15 22:29:06.869927
1134 1186,193,test1234124890814,224,gnomon,"",user_created_repo,2012-09-15 22:29:06.906648
1135 1187,207,D21,225,Some-fork,"",started_following_repo,2012-09-16 07:54:31.811337
1136 1188,207,D21,99,another-fork-to-check-code-review,"",user_forked_repo:Some-fork,2012-09-16 07:54:31.928503
1137 1189,207,D21,225,Some-fork,"",user_created_fork:Some-fork,2012-09-16 07:54:31.937372
1138 1190,3,demo,68,aaa-project,"",stopped_following_repo,2012-09-17 02:37:55.405711
1139 1191,3,demo,68,aaa-project,"",started_following_repo,2012-09-17 02:37:56.743644
1140 1192,3,demo,32,big-project,"",push_local:90f0247f654982a4dbc9e4861418c595a683e955,2012-09-17 02:40:47.259763
1141 1193,3,demo,32,big-project,"",user_commented_revision:90f0247f654982a4dbc9e4861418c595a683e955,2012-09-17 02:42:22.067682
1142 1194,3,demo,32,big-project,"",user_commented_revision:90f0247f654982a4dbc9e4861418c595a683e955,2012-09-17 02:43:53.288729
1143 1195,3,demo,32,big-project,"",user_commented_revision:90f0247f654982a4dbc9e4861418c595a683e955,2012-09-17 02:44:53.446591
1144 1196,3,demo,32,big-project,"",user_commented_revision:90f0247f654982a4dbc9e4861418c595a683e955,2012-09-17 02:45:25.720276
1145 1197,210,NewJoker,226,Game-Pomba,"",started_following_repo,2012-09-17 19:42:40.085447
1146 1198,210,NewJoker,226,Game-Pomba,"",user_created_repo,2012-09-17 19:42:40.098774
1147 1199,210,NewJoker,226,Game-Pomba,200.145.158.30,"push:82cbee64e8bf751654f39b6cef522575394d2b39,428505e2393b901562daac11bc050f449cb4418c,79c5e73e770d002472ee117b099b998b1897f140,67c5815cf9810a07a4edcfb63a6801a230149225",2012-09-17 19:43:52.544873
1148 1200,210,NewJoker,226,Game-Pomba,"",user_updated_repo,2012-09-17 19:51:20.717504
1149 1201,210,NewJoker,226,Game-Pomba,"",user_updated_repo,2012-09-17 19:54:17.369104
1150 1202,211,hmcaio,226,Game-Pomba,200.145.158.30,pull,2012-09-17 20:06:05.58778
1151 1203,108,dukeofgaming,124,fork-another-fork-to-check-code-review,"",user_updated_repo,2012-09-18 22:11:32.262653
1152 1204,3,demo,227,fork-aaa-project-2,"",started_following_repo,2012-09-19 05:04:47.237996
1153 1205,3,demo,68,aaa-project,"",user_forked_repo:fork-aaa-project-2,2012-09-19 05:04:47.261047
1154 1206,3,demo,227,fork-aaa-project-2,"",user_created_fork:fork-aaa-project-2,2012-09-19 05:04:47.275211
1155 1207,203,f.ludwig,223,florian-test-fork,"",user_commented_revision:028186940dbf5db5818c2c0a9ff80f214da0fd3f,2012-09-19 10:34:12.945275
1156 1208,203,f.ludwig,223,florian-test-fork,"",user_commented_revision:028186940dbf5db5818c2c0a9ff80f214da0fd3f,2012-09-19 10:34:21.140947
1157 1209,203,f.ludwig,223,florian-test-fork,"",user_commented_revision:028186940dbf5db5818c2c0a9ff80f214da0fd3f,2012-09-19 10:34:26.061929
1158 1210,1,default,68,aaa-project,74.125.184.38,pull,2012-09-19 15:23:03.784613
1159 1211,3,demo,68,aaa-project,74.125.184.23,push:8c632d9ca9fa402f585385c3bbadc139d6d085a9,2012-09-19 15:24:52.655487
1160 1212,214,am385,228,Testbed101,"",started_following_repo,2012-09-19 20:56:01.838629
1161 1213,214,am385,228,Testbed101,"",user_created_repo,2012-09-19 20:56:01.853795
1162 1214,214,am385,228,Testbed101,"",push_local:20cfcd314a6eae3cc3f83ac57e3f3d0bfbd12bfa,2012-09-19 21:02:39.003808
1163 1215,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:d5422faf648cc589425cd3b0dbf1f6dbf93036a0,2012-09-20 00:05:46.898686
1164 1216,1,default,122,amab,64.0.193.29,pull,2012-09-20 08:28:43.327263
1165 1217,3,demo,205,releases/fork-Sopra_testgd,"",user_commented_revision:99095f2d5703cbc43294ef55a19c5cc9e4cc2c15,2012-09-20 09:35:54.589279
1166 1218,3,demo,205,releases/fork-Sopra_testgd,"",user_commented_revision:99095f2d5703cbc43294ef55a19c5cc9e4cc2c15,2012-09-20 09:37:33.380842
1167 1219,3,demo,204,releases/Sopra_testgd,"",user_commented_pull_request:46,2012-09-20 09:38:40.617161
1168 1220,3,demo,204,releases/Sopra_testgd,"",user_closed_pull_request:46,2012-09-20 09:38:40.624018
1169 1221,3,demo,229,blaat,"",started_following_repo,2012-09-20 19:20:37.921692
1170 1222,3,demo,229,blaat,"",user_created_repo,2012-09-20 19:20:37.930827
1171 1223,3,demo,34,a,"",user_commented_revision:f437e821a406d35b1e231c5a81e82853f8ed6436,2012-09-20 20:07:29.000255
1172 1224,3,demo,230,eks1,"",started_following_repo,2012-09-20 20:42:54.376374
1173 1225,3,demo,230,eks1,"",user_created_repo,2012-09-20 20:42:54.385712
1174 1226,3,demo,230,eks1,216.191.220.77,push:f58be25d36113902d50783abb44d7bcbc62e4eb7,2012-09-20 20:46:36.378744
1175 1227,1,default,230,eks1,216.191.220.77,pull,2012-09-20 20:47:13.533037
1176 1228,3,demo,230,eks1,216.191.220.77,push:cc064b1c1831e9b5b1db6b9c72a7404b111b579a,2012-09-20 20:47:42.815309
1177 1229,1,default,230,eks1,216.191.220.77,pull,2012-09-20 20:47:53.706376
1178 1230,1,default,230,eks1,216.191.220.77,pull,2012-09-20 20:47:58.020108
1179 1231,3,demo,230,eks1,"",user_commented_revision:f58be25d36113902d50783abb44d7bcbc62e4eb7,2012-09-20 20:48:53.742614
1180 1232,3,demo,230,eks1,"",user_commented_revision:cc064b1c1831e9b5b1db6b9c72a7404b111b579a,2012-09-20 20:49:30.403129
1181 1233,3,demo,231,fork-eks1,"",started_following_repo,2012-09-20 20:51:24.23117
1182 1234,3,demo,230,eks1,"",user_forked_repo:fork-eks1,2012-09-20 20:51:24.242627
1183 1235,3,demo,231,fork-eks1,"",user_created_fork:fork-eks1,2012-09-20 20:51:24.249831
1184 1236,1,default,231,fork-eks1,216.191.220.77,pull,2012-09-20 20:51:52.699176
1185 1237,3,demo,231,fork-eks1,216.191.220.77,push:7be3eb971e236dd0c1d7b7c4637e7fab9c0a8eff,2012-09-20 20:52:17.107154
1186 1238,3,demo,230,eks1,"",user_commented_pull_request:53,2012-09-20 20:57:09.709452
1187 1239,3,demo,230,eks1,"",user_commented_pull_request:53,2012-09-20 20:59:58.813611
1188 1240,3,demo,230,eks1,"",user_closed_pull_request:53,2012-09-20 20:59:58.820711
1189 1241,3,demo,230,eks1,"",user_commented_pull_request:54,2012-09-20 21:02:22.161549
1190 1242,3,demo,230,eks1,"",user_closed_pull_request:54,2012-09-20 21:02:22.167313
1191 1243,1,default,231,fork-eks1,216.191.220.77,pull,2012-09-20 23:22:45.505072
1192 1244,3,demo,230,eks1,216.191.220.77,push:7be3eb971e236dd0c1d7b7c4637e7fab9c0a8eff,2012-09-20 23:24:42.752414
1193 1245,3,demo,231,fork-eks1,216.191.220.77,push:1a4b7771bd03e57d3a9854efd18de0d7d66db5d8,2012-09-20 23:25:49.109081
1194 1246,216,eks,232,eks1-eksfork,"",started_following_repo,2012-09-20 23:33:21.433073
1195 1247,216,eks,230,eks1,"",user_forked_repo:eks1-eksfork,2012-09-20 23:33:21.446723
1196 1248,216,eks,232,eks1-eksfork,"",user_created_fork:eks1-eksfork,2012-09-20 23:33:21.453956
1197 1249,1,default,232,eks1-eksfork,216.191.220.77,pull,2012-09-20 23:36:06.736653
1198 1250,1,default,122,amab,176.9.28.203,pull,2012-09-21 01:56:49.09876
1199 1251,3,demo,233,clonetest,"",started_following_repo,2012-09-21 01:56:49.309535
1200 1252,3,demo,233,clonetest,"",user_created_repo,2012-09-21 01:56:49.327352
1201 1253,217,domvign,234,fork2-tord,"",started_following_repo,2012-09-21 03:45:07.090078
1202 1254,217,domvign,201,tord,"",user_forked_repo:fork2-tord,2012-09-21 03:45:07.111893
1203 1255,217,domvign,234,fork2-tord,"",user_created_fork:fork2-tord,2012-09-21 03:45:07.125832
1204 1256,3,demo,235,test_test1,"",started_following_repo,2012-09-21 08:25:55.301672
1205 1257,3,demo,235,test_test1,"",user_created_repo,2012-09-21 08:25:55.312484
1206 1258,3,demo,235,test_test1,"",push_local:49f5d4efef5c24a6c82f3f56c750f6bd29d7e65c,2012-09-21 08:27:48.618627
1207 1259,3,demo,197,CollectionQuery,"",user_commented_revision:c51ad09cfdf5ae85a70c0210febc2692bdd0e0db,2012-09-21 10:14:32.510501
1208 1260,218,akesterson,236,myfork-CollectionQuery,"",started_following_repo,2012-09-21 14:45:19.861126
1209 1261,218,akesterson,197,CollectionQuery,"",user_forked_repo:myfork-CollectionQuery,2012-09-21 14:45:19.889428
1210 1262,218,akesterson,236,myfork-CollectionQuery,"",user_created_fork:myfork-CollectionQuery,2012-09-21 14:45:19.903413
1211 1263,218,akesterson,236,myfork-CollectionQuery,"",push_local:02029afb80de14455a4226a4a77b760b895aff7e,2012-09-21 14:46:12.771297
1212 1264,218,akesterson,236,myfork-CollectionQuery,"",push_local:2def3b046d2221aba86f5c9f1adb7259725bc8f5,2012-09-21 14:46:37.060973
1213 1265,218,akesterson,237,fork-myfork-CollectionQuery,"",started_following_repo,2012-09-21 14:48:05.149741
1214 1266,218,akesterson,236,myfork-CollectionQuery,"",user_forked_repo:fork-myfork-CollectionQuery,2012-09-21 14:48:05.166032
1215 1267,218,akesterson,237,fork-myfork-CollectionQuery,"",user_created_fork:fork-myfork-CollectionQuery,2012-09-21 14:48:05.176775
1216 1268,218,akesterson,237,fork-myfork-CollectionQuery,"",push_local:2300a2cb9c42bf638a156fcbe8cebfed710bd8e6,2012-09-21 14:49:48.45509
1217 1269,218,akesterson,236,myfork-CollectionQuery,"",user_commented_pull_request:57,2012-09-21 14:51:01.214716
1218 1270,218,akesterson,236,myfork-CollectionQuery,"",user_commented_pull_request:58,2012-09-21 14:52:20.163131
1219 1271,218,akesterson,236,myfork-CollectionQuery,"",user_closed_pull_request:58,2012-09-21 14:52:20.17166
1220 1275,218,akesterson,237,fork-myfork-CollectionQuery,"",push_local:73fcef6d2abe2dc061da59086561c7854266a78c,2012-09-21 14:56:02.339532
1221 1276,218,akesterson,238,fork2-myfork-CollectionQuery,"",started_following_repo,2012-09-21 15:11:55.391857
1222 1277,218,akesterson,236,myfork-CollectionQuery,"",user_forked_repo:fork2-myfork-CollectionQuery,2012-09-21 15:11:55.415225
1223 1278,218,akesterson,238,fork2-myfork-CollectionQuery,"",user_created_fork:fork2-myfork-CollectionQuery,2012-09-21 15:11:55.429075
1224 1279,218,akesterson,238,fork2-myfork-CollectionQuery,"",push_local:c29afd42fdfc5ef1d786ba0575a72c6a7991887b,2012-09-21 15:12:20.646365
1225 1280,218,akesterson,236,myfork-CollectionQuery,"",user_commented_pull_request:59,2012-09-21 15:13:11.024446
1226 1281,218,akesterson,236,myfork-CollectionQuery,"",user_commented_pull_request:59,2012-09-21 15:14:21.074425
1227 1282,218,akesterson,236,myfork-CollectionQuery,"",user_closed_pull_request:59,2012-09-21 15:14:21.083354
1228 1283,27,test123,38,code-review-test,"",user_commented_revision:125ff5654b72009b251706d7ee93051853f066b6,2012-09-21 20:57:25.108349
1229 1284,27,test123,38,code-review-test,"",user_commented_revision:125ff5654b72009b251706d7ee93051853f066b6,2012-09-21 20:58:03.041734
1230 1285,3,demo,233,clonetest,"",user_commented_revision:8530d8e3eab04997ac4a2a5d8a8b54fa61bb9884,2012-09-23 15:45:55.650268
1231 1286,3,demo,197,CollectionQuery,"",stopped_following_repo,2012-09-23 15:47:09.082723
1232 1287,3,demo,197,CollectionQuery,"",started_following_repo,2012-09-23 15:47:10.981914
1233 1288,3,demo,42,foo,"",user_updated_repo,2012-09-24 08:58:54.191524
1234 1289,3,demo,1,test,"",user_commented_pull_request:60,2012-09-24 20:09:58.857304
1235 1290,3,demo,239,w,"",started_following_repo,2012-09-25 05:06:46.054337
1236 1291,3,demo,239,w,"",user_created_repo,2012-09-25 05:06:46.066475
1237 1292,3,demo,240,superTest,"",started_following_repo,2012-09-25 05:07:49.733782
1238 1293,3,demo,240,superTest,"",user_created_repo,2012-09-25 05:07:49.743076
1239 1294,3,demo,34,a,"",user_updated_repo,2012-09-25 05:16:48.876018
1240 1295,3,demo,241,fork-a2,"",started_following_repo,2012-09-25 10:40:13.278898
1241 1296,3,demo,34,a,"",user_forked_repo:fork-a2,2012-09-25 10:40:13.299758
1242 1297,3,demo,241,fork-a2,"",user_created_fork:fork-a2,2012-09-25 10:40:13.313299
1243 1298,3,demo,241,fork-a2,"",push_local:7f7ca797917c69ae6cfdab99b428fe67aebd764d,2012-09-25 10:40:41.937706
1244 1299,3,demo,34,a,"",user_commented_pull_request:61,2012-09-25 10:43:24.263815
1245 1300,3,demo,34,a,"",user_closed_pull_request:61,2012-09-25 10:43:24.268374
1246 1301,3,demo,242,testtest,"",started_following_repo,2012-09-25 19:58:30.104927
1247 1302,3,demo,242,testtest,"",user_created_repo,2012-09-25 19:58:30.114632
1248 1303,3,demo,242,testtest,50.76.185.37,"push:82cc04e644fb4ac2202d6d38c3f98e1ac583fbd9,0c51202e5f9ac63b0f54eb5229f1850b430c3186,e5b80b681b96b37265d212ff97f655ae97f920c9,bacfc2c685668fb52d13bf438086167929628a4e,19a96e811fcce0440161ac77fa28feb608edfbc6,5a35e5e9d69b0d84199ca2477f596e0684f1d632,643146ee8f6e0798c2a6a6fdbe4dce9eff7776f2,6a0c17c8020c04ab67e055d4c4aec03e29ca7ad6,978d9e35d3bb27a2ef3b2fec04a15492f1d61970,bc1cc5164ef4bad7bbdb17caf14894f92d5d111f,331d14ee58a0530c7fd3c41537b4d247ae9d9ad6,404df8cdf4d474f97420a830d01aee7fbd2ea776,e2930d41a1769be193c2605be14532f3cc2cc162,59ae718e69abd66a3014356bf876f66db2a874b8,96163b25ae03a682d0582d4033649ee58e0fccee,66bada0d3d62a4b4b92de4e3e8d4b02d765a7326,63c17351ec88d5628ba7a2ce01ff08d1f519d7e2,e2949eadc403df055a58c7e0892926e53c38f872,2faef02e93acd948fcce2279d6d6f81da7e3a301,5e919a6fd85fab8b90a8b62d00e463dfcc4d21b6,06ebdbdf1a1b41a7c050d52a022be408a1437951,d37662b26d07c70ad4b4732fac696a7e7fa9685c,e07b358c22daf4e8b45e4ab869c1137c2b7dd0d5,d82075dcdcec0739ddcad0bcb96b671f6a3d3c7b,6866e9be9fde15aaf2a8639a931410089275db45,977fa64f7f1bd526a04cbc701683e3b789221a9c,ca4d6af6c64afeb8d4589002421038314ead455a",2012-09-25 19:59:54.485036
1249 1304,3,demo,34,a,"",push_local:98b22b6458fc028d5b8beb740d39372e72d8f41f,2012-09-25 21:22:16.676417
1250 1305,3,demo,34,a,76.112.55.52,pull,2012-09-25 21:26:13.528081
1251 1306,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-09-26 15:07:40.4856
1252 1307,3,demo,243,SR3HF2,"",started_following_repo,2012-09-26 16:53:58.744798
1253 1308,3,demo,243,SR3HF2,"",user_created_repo,2012-09-26 16:53:58.760782
1254 1309,3,demo,243,SR3HF2,"",push_local:d9cf639344ea84f1a5c57f9ce10c043f1b446e08,2012-09-26 17:05:27.808045
1255 1310,3,demo,243,SR3HF2,"",user_updated_repo,2012-09-26 17:10:30.366062
1256 1311,3,demo,243,SR3HF2,"",user_updated_repo,2012-09-26 17:11:11.747863
1257 1312,3,demo,243,SR3HF2,"",user_updated_repo,2012-09-26 17:11:48.355287
1258 1313,230,AstrasyA,244,Sonny,"",started_following_repo,2012-09-26 17:43:33.022333
1259 1314,230,AstrasyA,244,Sonny,"",user_created_repo,2012-09-26 17:43:33.033696
1260 1315,230,AstrasyA,244,Sonny,"",push_local:9732b5c4fdde74545ca40878530e804712c4e445,2012-09-26 17:44:35.341457
1261 1316,230,AstrasyA,244,Sonny,50.84.107.130,pull,2012-09-26 17:59:06.387257
1262 1317,230,AstrasyA,244,Sonny,50.84.107.130,"push:98d933718544ec91d426b6b37f091f6f0501b3dc,334ac777d05f4653887569cb2b68ea7c255cf929",2012-09-26 18:27:38.08683
1263 1318,230,AstrasyA,244,Sonny,50.84.107.130,push:57eaee8ade535415036f1e9fada104edd1db8389,2012-09-26 18:43:41.784818
1264 1319,230,AstrasyA,244,Sonny,"",user_commented_revision:57eaee8ade535415036f1e9fada104edd1db8389,2012-09-26 19:34:58.000965
1265 1320,230,AstrasyA,244,Sonny,"",user_commented_revision:57eaee8ade535415036f1e9fada104edd1db8389,2012-09-26 19:35:02.910074
1266 1321,230,AstrasyA,244,Sonny,"",user_commented_revision:57eaee8ade535415036f1e9fada104edd1db8389,2012-09-26 19:35:13.500416
1267 1322,230,AstrasyA,244,Sonny,"",user_commented_revision:57eaee8ade535415036f1e9fada104edd1db8389,2012-09-26 19:37:13.951346
1268 1323,230,AstrasyA,244,Sonny,"",user_commented_revision:57eaee8ade535415036f1e9fada104edd1db8389,2012-09-26 19:37:19.504417
1269 1324,3,demo,245,SubrepoTest,"",started_following_repo,2012-09-26 21:03:21.25341
1270 1325,3,demo,245,SubrepoTest,"",user_created_repo,2012-09-26 21:03:21.266132
1271 1326,3,demo,246,SubrepoTest-subrepo,"",started_following_repo,2012-09-26 21:04:08.921652
1272 1327,3,demo,246,SubrepoTest-subrepo,"",user_created_repo,2012-09-26 21:04:08.935788
1273 1328,230,AstrasyA,244,Sonny,50.84.107.130,"push:4d583f24f1984fd21a8038d60ae510cd8e0d5b8c,8543508ae6664832fe59cd4f6587add1b69c6db3",2012-09-26 22:49:33.613712
1274 1329,230,AstrasyA,244,Sonny,"",user_commented_revision:4d583f24f1984fd21a8038d60ae510cd8e0d5b8c,2012-09-26 22:54:09.170876
1275 1330,230,AstrasyA,244,Sonny,"",user_commented_revision:4d583f24f1984fd21a8038d60ae510cd8e0d5b8c,2012-09-26 22:54:21.612237
1276 1331,1,default,159,group/Test-for-code-review,"",push_local:4471d93e69c9abb14c65ac96a349fd642269a337,2012-09-27 01:26:37.747241
1277 1332,231,asdf,247,fork-a-fork1,"",started_following_repo,2012-09-27 02:13:08.518743
1278 1333,231,asdf,90,a-fork1,"",user_forked_repo:fork-a-fork1,2012-09-27 02:13:08.536794
1279 1334,231,asdf,247,fork-a-fork1,"",user_created_fork:fork-a-fork1,2012-09-27 02:13:08.54404
1280 1335,3,demo,248,_KBTEST,"",started_following_repo,2012-09-27 06:39:50.386213
1281 1336,3,demo,248,_KBTEST,"",user_created_repo,2012-09-27 06:39:50.395378
1282 1337,232,demo123,249,abcdefg,"",started_following_repo,2012-09-27 09:46:45.351423
1283 1338,232,demo123,127,my-super-rep,"",user_forked_repo:abcdefg,2012-09-27 09:46:45.389459
1284 1339,232,demo123,249,abcdefg,"",user_created_fork:abcdefg,2012-09-27 09:46:45.396765
1285 1340,232,demo123,249,abcdefg,"",push_local:ef6c825bc5699b95a31ae3075693b12693a623e2,2012-09-27 09:48:20.630491
1286 1341,232,demo123,127,my-super-rep,"",user_commented_pull_request:62,2012-09-27 09:50:27.609218
1287 1342,232,demo123,127,my-super-rep,"",user_commented_pull_request:62,2012-09-27 09:50:44.558277
1288 1343,232,demo123,127,my-super-rep,"",user_commented_pull_request:62,2012-09-27 09:51:28.711229
1289 1344,1,default,159,group/Test-for-code-review,"",push_local:f7383651e85c99e62e22e662b137790efa70660c,2012-09-27 11:10:12.51927
1290 1345,233,mecoder,250,mecodertest,"",started_following_repo,2012-09-27 12:22:22.89884
1291 1346,233,mecoder,250,mecodertest,"",user_created_repo,2012-09-27 12:22:22.907773
1292 1347,77,test,251,test1234,"",started_following_repo,2012-09-27 14:22:54.649441
1293 1348,77,test,251,test1234,"",user_created_repo,2012-09-27 14:22:54.658343
1294 1349,1,default,86,qbtest,"",push_local:3875428f3bdcab3cfa74759a40182c6a643e4203,2012-09-27 14:49:57.797524
1295 1350,3,demo,252,Test-repo,"",started_following_repo,2012-09-27 20:14:53.658366
1296 1351,3,demo,252,Test-repo,"",user_created_repo,2012-09-27 20:14:53.667343
1297 1352,3,demo,252,Test-repo,"",user_updated_repo,2012-09-27 20:16:25.412816
1298 1353,235,wryfi,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-09-27 21:40:52.517897
1299 1354,235,wryfi,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-09-27 21:41:45.427104
1300 1355,1,default,86,qbtest,"",push_local:bed2107c6d7286a5645a27da26183fe6035e58ef,2012-09-28 01:02:08.90859
1301 1356,1,default,68,aaa-project,24.237.22.151,pull,2012-09-28 02:40:56.789606
1302 1357,1,default,68,aaa-project,24.237.22.151,pull,2012-09-28 02:41:08.302352
1303 1358,1,default,159,group/Test-for-code-review,"",push_local:56533e7a81a9c1c68125dc45ac78c050791fd0a2,2012-09-28 10:06:43.559824
1304 1359,2,admin,,"","",admin_created_user:ip,2012-09-28 22:22:59.371488
1305 1360,2,admin,253,ip,"",started_following_repo,2012-09-28 22:23:19.263438
1306 1361,2,admin,253,ip,"",admin_created_repo,2012-09-28 22:23:19.277556
1307 1362,2,admin,253,ip,"",admin_updated_repo,2012-09-28 22:24:27.358795
1308 1363,2,admin,253,ip,"",admin_updated_repo,2012-09-28 22:24:40.194254
1309 1364,2,admin,253,ip,"",admin_updated_repo,2012-09-28 22:25:03.078491
1310 1365,2,admin,253,ip,"",admin_updated_repo,2012-09-28 22:25:25.793178
1311 1366,2,admin,253,ip,"",admin_updated_repo,2012-09-28 22:25:35.065161
1312 1367,1,default,159,group/Test-for-code-review,"",push_local:6900b7e43c402939ee2d058b8ad94cce31cb6dcd,2012-09-29 00:17:35.860963
1313 1368,1,default,86,qbtest,"",push_local:73eb33fa1edfc909f673d128bac55bd175aa7559,2012-09-29 02:34:11.898184
1314 1369,3,demo,68,aaa-project,"",push_local:b4bf1f77b1288a24eb395537319b4f3155cffa71,2012-09-29 15:24:51.088586
1315 1370,1,default,86,qbtest,"",push_local:f8647a38fa4e07d3a2dc96add8944581b31ebec5,2012-09-29 15:57:39.603006
1316 1371,1,default,159,group/Test-for-code-review,"",push_local:b5c5b6f1112b43442d09a889212e132a93f5793d,2012-09-29 22:12:56.345343
1317 1372,1,default,86,qbtest,"",push_local:bd704836ab78a54cfeb4819a781ff6371fad01bc,2012-09-30 14:33:42.755143
1318 1373,244,dantascione,254,dantest,"",started_following_repo,2012-09-30 23:39:17.975735
1319 1374,244,dantascione,254,dantest,"",user_created_repo,2012-09-30 23:39:17.98529
1320 1375,245,charlouze,255,Testtest,"",started_following_repo,2012-10-01 11:19:43.687453
1321 1376,245,charlouze,255,Testtest,"",user_created_repo,2012-10-01 11:19:43.696384
1322 1377,245,charlouze,255,Testtest,"",push_local:ac7c39aa78a1d0c799881d699d8565b0816cc178,2012-10-01 11:20:31.326931
1323 1378,245,charlouze,255,Testtest,"",user_commented_revision:ac7c39aa78a1d0c799881d699d8565b0816cc178,2012-10-01 11:23:58.997838
1324 1379,245,charlouze,255,Testtest,"",user_commented_revision:ac7c39aa78a1d0c799881d699d8565b0816cc178,2012-10-01 11:24:31.208917
1325 1380,245,charlouze,255,Testtest,"",user_commented_revision:ac7c39aa78a1d0c799881d699d8565b0816cc178,2012-10-01 11:26:15.205171
1326 1381,245,charlouze,255,Testtest,"",user_commented_revision:ac7c39aa78a1d0c799881d699d8565b0816cc178,2012-10-01 11:28:48.152422
1327 1382,5,natosha.bard,256,unity-test-trunk,"",started_following_repo,2012-10-01 12:54:48.012856
1328 1383,5,natosha.bard,256,unity-test-trunk,"",user_created_repo,2012-10-01 12:54:48.021667
1329 1384,5,natosha.bard,256,unity-test-trunk,62.116.219.97,push:5dfe4faa4f9adf73694cf8bb5d35ef0accc5d8b5,2012-10-01 12:57:11.503947
1330 1385,5,natosha.bard,257,fork-unity-test-trunk,"",started_following_repo,2012-10-01 12:57:33.430298
1331 1386,5,natosha.bard,256,unity-test-trunk,"",user_forked_repo:fork-unity-test-trunk,2012-10-01 12:57:33.441529
1332 1387,5,natosha.bard,257,fork-unity-test-trunk,"",user_created_fork:fork-unity-test-trunk,2012-10-01 12:57:33.448865
1333 1388,5,natosha.bard,256,unity-test-trunk,"",user_commented_revision:5dfe4faa4f9adf73694cf8bb5d35ef0accc5d8b5,2012-10-01 12:58:09.430931
1334 1389,5,natosha.bard,258,fork-unity-test-trunk2,"",started_following_repo,2012-10-01 12:58:19.082884
1335 1390,5,natosha.bard,256,unity-test-trunk,"",user_forked_repo:fork-unity-test-trunk2,2012-10-01 12:58:19.095714
1336 1391,5,natosha.bard,258,fork-unity-test-trunk2,"",user_created_fork:fork-unity-test-trunk2,2012-10-01 12:58:19.103935
1337 1392,5,natosha.bard,257,fork-unity-test-trunk,62.116.219.97,push:591581862d50c7439243a7ef92d7638a5c88e6be,2012-10-01 12:59:48.814795
1338 1393,5,natosha.bard,257,fork-unity-test-trunk,"",user_commented_revision:591581862d50c7439243a7ef92d7638a5c88e6be,2012-10-01 13:00:18.872593
1339 1394,5,natosha.bard,259,fork-fork-unity-test-trunk,"",started_following_repo,2012-10-01 13:00:29.763296
1340 1395,5,natosha.bard,257,fork-unity-test-trunk,"",user_forked_repo:fork-fork-unity-test-trunk,2012-10-01 13:00:29.774818
1341 1396,5,natosha.bard,259,fork-fork-unity-test-trunk,"",user_created_fork:fork-fork-unity-test-trunk,2012-10-01 13:00:29.782337
1342 1397,1,default,259,fork-fork-unity-test-trunk,62.116.219.97,pull,2012-10-01 13:00:44.100787
1343 1398,5,natosha.bard,259,fork-fork-unity-test-trunk,62.116.219.97,push:2d2486009a875d8d98667aef38451560fe93e763,2012-10-01 13:01:55.725508
1344 1399,5,natosha.bard,260,fork-code-review-test2,"",started_following_repo,2012-10-01 14:08:47.077755
1345 1400,5,natosha.bard,38,code-review-test,"",user_forked_repo:fork-code-review-test2,2012-10-01 14:08:47.376389
1346 1401,5,natosha.bard,260,fork-code-review-test2,"",user_created_fork:fork-code-review-test2,2012-10-01 14:08:47.383934
1347 1402,1,default,260,fork-code-review-test2,62.116.219.97,pull,2012-10-01 14:09:42.365103
1348 1405,3,demo,261,subrepotest,"",started_following_repo,2012-10-02 10:44:47.066589
1349 1406,3,demo,261,subrepotest,"",user_created_repo,2012-10-02 10:44:47.075524
1350 1407,3,demo,262,subrepotest-subrepo,"",started_following_repo,2012-10-02 10:45:45.448349
1351 1408,3,demo,262,subrepotest-subrepo,"",user_created_repo,2012-10-02 10:45:45.457209
1352 1409,1,default,68,aaa-project,64.208.49.214,pull,2012-10-02 10:58:33.566475
1353 1410,3,demo,68,aaa-project,64.208.49.214,push:0c33fa58efc5a5541d8d3f1a3d3b77367e3d94f5,2012-10-02 10:59:53.3117
1354 1411,3,demo,263,ronka,"",started_following_repo,2012-10-02 20:07:51.923475
1355 1412,3,demo,263,ronka,"",user_created_repo,2012-10-02 20:07:51.935377
1356 1413,3,demo,263,ronka,"",push_local:1f91226c774447604a289d0bed9e05f83432fcbe,2012-10-02 20:08:15.849135
1357 1414,3,demo,264,fork-ronka,"",started_following_repo,2012-10-02 20:10:09.612131
1358 1415,3,demo,263,ronka,"",user_forked_repo:fork-ronka,2012-10-02 20:10:09.633433
1359 1416,3,demo,264,fork-ronka,"",user_created_fork:fork-ronka,2012-10-02 20:10:09.647288
1360 1417,3,demo,264,fork-ronka,"",push_local:4459658481bad662eb53b308fcf2c0f08fc03d9d,2012-10-02 20:11:23.190731
1361 1418,3,demo,263,ronka,"",user_commented_pull_request:64,2012-10-02 20:12:47.073638
1362 1419,3,demo,263,ronka,"",user_closed_pull_request:64,2012-10-02 20:12:47.080999
1363 1420,3,demo,263,ronka,"",user_commented_revision:1f91226c774447604a289d0bed9e05f83432fcbe,2012-10-02 20:17:57.594034
1364 1421,3,demo,110,django,"",user_commented_revision:129f1ac8484d63c2e61a44fb2a18dd17246c1c4d,2012-10-03 08:51:36.810037
1365 1422,3,demo,110,django,"",user_commented_revision:129f1ac8484d63c2e61a44fb2a18dd17246c1c4d,2012-10-03 08:52:06.456456
1366 1423,3,demo,127,my-super-rep,"",push_local:a43642a9b5a96ede38c20f64fc58827a8f20e276,2012-10-03 17:18:49.819491
1367 1424,5,natosha.bard,265,mercurial-trunk,"",started_following_repo,2012-10-04 11:41:46.868234
1368 1425,5,natosha.bard,265,mercurial-trunk,"",user_created_repo,2012-10-04 11:41:46.878607
1369 1427,5,natosha.bard,266,fork-mercurial-trunk,"",started_following_repo,2012-10-04 11:44:29.692682
1370 1428,5,natosha.bard,265,mercurial-trunk,"",user_forked_repo:fork-mercurial-trunk,2012-10-04 11:44:29.748996
1371 1429,5,natosha.bard,266,fork-mercurial-trunk,"",user_created_fork:fork-mercurial-trunk,2012-10-04 11:44:29.756625
1372 1431,246,stilvoid,267,fork-florian-test,"",started_following_repo,2012-10-04 11:54:18.90186
1373 1432,246,stilvoid,222,florian-test,"",user_forked_repo:fork-florian-test,2012-10-04 11:54:18.931691
1374 1433,246,stilvoid,267,fork-florian-test,"",user_created_fork:fork-florian-test,2012-10-04 11:54:18.939443
1375 1434,5,natosha.bard,266,fork-mercurial-trunk,62.116.219.97,push:f11d82b04ca50abb59ad6cfbb16fbd5022f45395,2012-10-04 12:54:36.544979
1376 1435,3,demo,268,foofootest,"",started_following_repo,2012-10-04 16:59:07.216586
1377 1436,3,demo,268,foofootest,"",user_created_repo,2012-10-04 16:59:07.226019
1378 1437,3,demo,268,foofootest,"unknown, 217.91.236.41",push:4bc0645c20363db85c9a5050a85c2c05a1991765,2012-10-04 16:59:59.645044
1379 1438,3,demo,269,fork-foofootest,"",started_following_repo,2012-10-04 17:00:11.539125
1380 1439,3,demo,268,foofootest,"",user_forked_repo:fork-foofootest,2012-10-04 17:00:11.631359
1381 1440,3,demo,269,fork-foofootest,"",user_created_fork:fork-foofootest,2012-10-04 17:00:11.639325
1382 1442,3,demo,270,fork-fork-code-review-test2-fork,"",started_following_repo,2012-10-04 20:42:33.068317
1383 1443,3,demo,260,fork-code-review-test2,"",user_forked_repo:fork-fork-code-review-test2-fork,2012-10-04 20:42:33.16905
1384 1444,3,demo,270,fork-fork-code-review-test2-fork,"",user_created_fork:fork-fork-code-review-test2-fork,2012-10-04 20:42:33.176787
1385 1445,1,default,68,aaa-project,77.120.252.31,pull,2012-10-05 13:46:02.97144
1386 1446,3,demo,271,ttt,"",started_following_repo,2012-10-05 14:18:30.594537
1387 1447,3,demo,271,ttt,"",user_created_repo,2012-10-05 14:18:30.637003
1388 1448,3,demo,272,tttt,"",started_following_repo,2012-10-05 14:19:42.35258
1389 1449,3,demo,272,tttt,"",user_created_repo,2012-10-05 14:19:42.364131
1390 1450,3,demo,273,dotemacs,"",started_following_repo,2012-10-06 06:10:59.614385
1391 1451,3,demo,273,dotemacs,"",user_created_repo,2012-10-06 06:10:59.624083
1392 1452,3,demo,273,dotemacs,202.120.38.18,push:9d237512de694be7b30e61b9e0373f0dc373fa24,2012-10-06 06:13:30.793795
1393 1453,249,shahin,274,kado,"",started_following_repo,2012-10-07 13:13:08.693172
1394 1454,249,shahin,274,kado,"",user_created_repo,2012-10-07 13:13:08.703331
1395 1455,249,shahin,274,kado,"",push_local:cb452956879bd22220e2513d7417d239e216813d,2012-10-07 13:14:26.479362
1396 1456,3,demo,275,TEST,"",started_following_repo,2012-10-07 22:32:01.007959
1397 1457,3,demo,275,TEST,"",user_created_repo,2012-10-07 22:32:01.017119
1398 1458,3,demo,276,my-wonderful-project,"",started_following_repo,2012-10-08 10:12:31.462976
1399 1459,3,demo,276,my-wonderful-project,"",user_created_repo,2012-10-08 10:12:31.474657
1400 1460,250,dessp,277,fork-fork-aaa-project,"",started_following_repo,2012-10-08 12:34:18.364871
1401 1461,250,dessp,184,fork-aaa-project,"",user_forked_repo:fork-fork-aaa-project,2012-10-08 12:34:18.383393
1402 1462,250,dessp,277,fork-fork-aaa-project,"",user_created_fork:fork-fork-aaa-project,2012-10-08 12:34:18.392037
1403 1463,250,dessp,278,bla,"",started_following_repo,2012-10-08 12:35:59.034211
1404 1464,250,dessp,278,bla,"",user_created_repo,2012-10-08 12:35:59.046964
1405 1465,250,dessp,278,bla,"",push_local:d67d6b2cd83c926cc98b7338dd375c0d7dc224ed,2012-10-08 12:36:23.610968
1406 1466,251,vaueff,279,meinsisses,"",started_following_repo,2012-10-08 17:11:28.309493
1407 1467,251,vaueff,206,test-sls,"",user_forked_repo:meinsisses,2012-10-08 17:11:28.333732
1408 1468,251,vaueff,279,meinsisses,"",user_created_fork:meinsisses,2012-10-08 17:11:28.34374
1409 1469,3,demo,280,HelloWorld,"",started_following_repo,2012-10-08 17:19:57.672859
1410 1470,3,demo,280,HelloWorld,"",user_created_repo,2012-10-08 17:19:57.685128
1411 1471,3,demo,127,my-super-rep,"",user_commented_pull_request:62,2012-10-08 17:37:04.554118
1412 1472,3,demo,127,my-super-rep,"",user_closed_pull_request:62,2012-10-08 17:37:04.56515
1413 1473,3,demo,249,abcdefg,"",user_commented_revision:ef6c825bc5699b95a31ae3075693b12693a623e2,2012-10-08 17:38:13.042926
1414 1474,254,yujiro,281,yujirotest,"",started_following_repo,2012-10-09 06:59:18.412429
1415 1475,254,yujiro,281,yujirotest,"",user_created_repo,2012-10-09 06:59:18.424128
1416 1476,254,yujiro,282,fork-amabあああ,"",started_following_repo,2012-10-09 07:03:34.289292
1417 1477,254,yujiro,122,amab,"",user_forked_repo:fork-amabあああ,2012-10-09 07:03:34.308792
1418 1478,254,yujiro,282,fork-amabあああ,"",user_created_fork:fork-amabあああ,2012-10-09 07:03:34.320104
1419 1479,254,yujiro,172,go,"",started_following_repo,2012-10-09 07:09:23.727527
1420 1480,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-10-09 08:44:14.777602
1421 1481,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-10-09 08:44:52.916854
1422 1482,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:30853f4bde2f2b6f0a7126392b9b1b4c5ea37e0a,2012-10-09 08:45:16.42599
1423 1483,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:30853f4bde2f2b6f0a7126392b9b1b4c5ea37e0a,2012-10-09 08:45:38.745859
1424 1484,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:30853f4bde2f2b6f0a7126392b9b1b4c5ea37e0a,2012-10-09 08:45:52.328248
1425 1485,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:30853f4bde2f2b6f0a7126392b9b1b4c5ea37e0a,2012-10-09 08:46:01.737145
1426 1486,255,che,283,test-zh-tw,"",started_following_repo,2012-10-09 10:33:51.971598
1427 1487,255,che,283,test-zh-tw,"",user_created_repo,2012-10-09 10:33:51.983333
1428 1488,255,che,283,test-zh-tw,"61.56.13.120, 61.56.15.166","push:ea3aa785b5f361e36ccdbb8201fa809cf0e9b371,bf62637068b19308263d2ed9cdd1b43ae3d88757",2012-10-09 10:36:13.255622
1429 1489,3,demo,284,fork-django,"",started_following_repo,2012-10-09 20:17:50.071294
1430 1490,3,demo,110,django,"",user_forked_repo:fork-django,2012-10-09 20:17:57.420156
1431 1491,3,demo,284,fork-django,"",user_created_fork:fork-django,2012-10-09 20:17:57.434345
1432 1492,3,demo,285,github-killer,"",started_following_repo,2012-10-09 21:05:48.6309
1433 1493,3,demo,285,github-killer,"",user_created_repo,2012-10-09 21:05:48.644556
1434 1494,3,demo,285,github-killer,188.25.172.123,push:df73f912eb7cd583d1fda6a4ef19c1ab1dbc6f92,2012-10-09 21:06:55.345622
1435 1495,3,demo,285,aloha,"",user_updated_repo,2012-10-09 21:13:16.792012
1436 1496,3,demo,127,my-super-rep,"",user_commented_revision:5d80e28538141e322b317168e2367fb03178d58c,2012-10-09 22:39:42.201647
1437 1497,3,demo,286,http-mercurial.selenic.com-hg,"",started_following_repo,2012-10-10 02:37:22.675764
1438 1498,3,demo,286,http-mercurial.selenic.com-hg,"",user_created_repo,2012-10-10 02:37:22.693066
1439 1499,3,demo,287,fork-http-mercurial.selenic.com-hg,"",started_following_repo,2012-10-10 02:38:04.918464
1440 1500,3,demo,286,http-mercurial.selenic.com-hg,"",user_forked_repo:fork-http-mercurial.selenic.com-hg,2012-10-10 02:38:05.085956
1441 1501,3,demo,287,fork-http-mercurial.selenic.com-hg,"",user_created_fork:fork-http-mercurial.selenic.com-hg,2012-10-10 02:38:05.094152
1442 1502,3,demo,287,fork-http-mercurial.selenic.com-hg,"",push_local:9ce0ab91b57ea15f5e8569ef7304ce58c9acf477,2012-10-10 02:39:19.103663
1443 1503,3,demo,286,http-mercurial.selenic.com-hg,"",user_commented_pull_request:66,2012-10-10 02:42:42.025549
1444 1504,3,demo,286,http-mercurial.selenic.com-hg,"",user_closed_pull_request:66,2012-10-10 02:42:42.034609
1445 1505,3,demo,287,fork-http-mercurial.selenic.com-hg,"",user_commented_revision:9ce0ab91b57ea15f5e8569ef7304ce58c9acf477,2012-10-10 02:44:45.999905
1446 1506,3,demo,287,fork-http-mercurial.selenic.com-hg,"",user_commented_revision:9ce0ab91b57ea15f5e8569ef7304ce58c9acf477,2012-10-10 02:44:51.716813
1447 1507,256,dg_test,288,dgtestrepo,"",started_following_repo,2012-10-10 04:48:48.801476
1448 1508,256,dg_test,288,dgtestrepo,"",user_created_repo,2012-10-10 04:48:48.813822
1449 1509,256,dg_test,288,dgtestrepo,59.167.167.230,push:27ab7e76abe80344db6a250d3a8979117907704a,2012-10-10 04:49:46.01297
1450 1510,256,dg_test,289,fork-dgtestrepo,"",started_following_repo,2012-10-10 04:50:15.108071
1451 1511,256,dg_test,288,dgtestrepo,"",user_forked_repo:fork-dgtestrepo,2012-10-10 04:50:15.127777
1452 1512,256,dg_test,289,fork-dgtestrepo,"",user_created_fork:fork-dgtestrepo,2012-10-10 04:50:15.141651
1453 1513,1,default,289,fork-dgtestrepo,59.167.167.230,pull,2012-10-10 04:50:29.22472
1454 1514,256,dg_test,289,fork-dgtestrepo,59.167.167.230,push:36da9693f7e90974c46bf83c9abdb4803fac13ff,2012-10-10 04:50:59.757989
1455 1515,256,dg_test,288,dgtestrepo,"",user_commented_pull_request:67,2012-10-10 04:51:51.635244
1456 1516,256,dg_test,288,dgtestrepo,"",user_commented_pull_request:67,2012-10-10 04:52:13.711421
1457 1517,256,dg_test,288,dgtestrepo,"",user_commented_pull_request:67,2012-10-10 04:54:11.518751
1458 1518,256,dg_test,288,dgtestrepo,"",user_commented_pull_request:67,2012-10-10 06:35:30.952227
1459 1519,1,default,289,fork-dgtestrepo,59.167.167.230,pull,2012-10-10 12:39:46.774029
1460 1520,256,dg_test,288,dgtestrepo,59.167.167.230,push:36da9693f7e90974c46bf83c9abdb4803fac13ff,2012-10-10 12:40:26.181044
1461 1521,256,dg_test,288,dgtestrepo,"",user_commented_pull_request:67,2012-10-10 12:41:54.987689
1462 1522,256,dg_test,288,dgtestrepo,"",user_commented_pull_request:67,2012-10-10 12:42:03.057669
1463 1523,256,dg_test,257,fork-unity-test-trunk,"",user_commented_pull_request:63,2012-10-10 12:47:14.298864
1464 1524,256,dg_test,288,dgtestrepo,"",user_commented_revision:36da9693f7e90974c46bf83c9abdb4803fac13ff,2012-10-10 12:49:30.180636
1465 1525,256,dg_test,288,dgtestrepo,"",user_commented_pull_request:67,2012-10-10 12:50:11.880937
1466 1526,256,dg_test,288,dgtestrepo,"",user_closed_pull_request:67,2012-10-10 12:50:11.885641
1467 1527,256,dg_test,290,dg1,"",started_following_repo,2012-10-10 13:00:18.072553
1468 1528,256,dg_test,290,dg1,"",user_created_repo,2012-10-10 13:00:18.084695
1469 1529,256,dg_test,291,fork-dg1,"",started_following_repo,2012-10-10 13:00:31.045836
1470 1530,256,dg_test,290,dg1,"",user_forked_repo:fork-dg1,2012-10-10 13:00:31.064079
1471 1531,256,dg_test,291,fork-dg1,"",user_created_fork:fork-dg1,2012-10-10 13:00:31.073556
1472 1538,256,dg_test,290,dg1,"",user_commented_pull_request:68,2012-10-10 13:04:05.221925
1473 1532,256,dg_test,290,dg1,59.167.167.230,push:c8996239abf9263cdee5b15234372e3a6e793e44,2012-10-10 13:01:40.777662
1474 1533,256,dg_test,292,fork-dg11,"",started_following_repo,2012-10-10 13:02:33.177064
1475 1534,256,dg_test,290,dg1,"",user_forked_repo:fork-dg11,2012-10-10 13:02:33.193349
1476 1535,256,dg_test,292,fork-dg11,"",user_created_fork:fork-dg11,2012-10-10 13:02:33.207706
1477 1536,1,default,292,fork-dg11,59.167.167.230,pull,2012-10-10 13:02:44.944887
1478 1537,256,dg_test,292,fork-dg11,59.167.167.230,push:667a6c5db8f25896ef1cadd1f5138898026f068e,2012-10-10 13:03:21.048735
1479 1540,256,dg_test,290,dg1,59.167.167.230,push:667a6c5db8f25896ef1cadd1f5138898026f068e,2012-10-10 13:04:47.505397
1480 1541,256,dg_test,290,dg1,"",user_commented_revision:667a6c5db8f25896ef1cadd1f5138898026f068e,2012-10-10 13:09:03.381076
1481 1539,256,dg_test,290,dg1,"",user_closed_pull_request:68,2012-10-10 13:04:05.229068
1482 1542,256,dg_test,288,dgtestrepo,"",user_commented_revision:36da9693f7e90974c46bf83c9abdb4803fac13ff,2012-10-10 13:20:40.664276
1483 1543,3,demo,38,code-review-test,"",user_commented_revision:6d7db5794e8cad7da042b6ae6238116c6e59a4d2,2012-10-10 21:33:13.589618
1484 1544,1,default,122,amab,75.128.117.162,pull,2012-10-11 04:26:13.01088
1485 1545,3,demo,294,fork-aloha,"",started_following_repo,2012-10-11 10:49:27.293629
1486 1546,3,demo,285,aloha,"",user_forked_repo:fork-aloha,2012-10-11 10:49:27.403491
1487 1547,3,demo,294,fork-aloha,"",user_created_fork:fork-aloha,2012-10-11 10:49:27.417952
1488 1548,2,admin,,"","",admin_created_user:user_rc_1,2012-10-11 12:16:48.505211
1489 1549,2,admin,,"","",admin_created_user:user_rc_2,2012-10-11 12:17:03.054922
1490 1550,3,demo,34,a,"",user_commented_revision:f437e821a406d35b1e231c5a81e82853f8ed6436,2012-10-11 12:17:37.00837
1491 1551,3,demo,34,a,"",user_commented_revision:f437e821a406d35b1e231c5a81e82853f8ed6436,2012-10-11 12:17:46.881784
1492 1552,3,demo,34,a,"",user_commented_revision:f437e821a406d35b1e231c5a81e82853f8ed6436,2012-10-11 12:23:44.417665
1493 1553,3,demo,122,amab,"",push_local:796c02c902e1098268c622e34e9526b7424c2f0a,2012-10-11 14:24:20.208902
1494 1554,3,demo,295,test333,"",started_following_repo,2012-10-11 14:33:32.412381
1495 1555,3,demo,295,test333,"",user_created_repo,2012-10-11 14:33:32.424562
1496 1556,3,demo,285,aloha,"",push_local:b59aa4775f36a3f553d2d9b9296b9272106b920d,2012-10-11 14:34:31.082462
1497 1557,3,demo,295,test333,62.153.70.3,"push:ee67bac620f0c1823f863be9e829efd5e3b34f42,a3c1ca826d1cc57132141e70ee7e9f77ecef43fe",2012-10-11 14:36:48.814768
1498 1558,3,demo,285,aloha,"",push_local:3266a55348986338e8cffb2b8605ba754a54497f,2012-10-11 14:37:57.513628
1499 1559,3,demo,285,aloha,"",push_local:8411bc8656efd477e0c817ebbbf448fe5ca0d5fa,2012-10-11 14:38:33.492779
1500 1560,3,demo,285,aloha,"",user_updated_repo,2012-10-11 14:43:08.034646
1501 1561,3,demo,285,aloha,"",user_updated_repo,2012-10-11 14:43:52.370534
1502 1562,260,kudtest,296,fork-amab-kud,"",started_following_repo,2012-10-11 15:02:21.701772
1503 1563,260,kudtest,122,amab,"",user_forked_repo:fork-amab-kud,2012-10-11 15:02:21.721067
1504 1564,260,kudtest,296,fork-amab-kud,"",user_created_fork:fork-amab-kud,2012-10-11 15:02:21.738079
1505 1565,3,demo,297,mytest,"",started_following_repo,2012-10-11 17:35:37.595048
1506 1566,3,demo,297,mytest,"",user_created_repo,2012-10-11 17:35:37.607661
1507 1567,3,demo,297,mytest,"",push_local:e9c241d5215f8bdfa8b0cabab229952b2740ee98,2012-10-11 17:37:50.954858
1508 1568,3,demo,297,mytest,"",user_updated_repo,2012-10-11 17:39:13.548988
1509 1569,37,tester,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-10-11 19:10:15.328087
1510 1570,37,tester,201,tord,"",user_commented_revision:35b3ebc8e1c23902eb97031f42f666df0835c5be,2012-10-11 19:19:55.616125
1511 1571,37,tester,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-10-11 19:24:45.086999
1512 1572,37,tester,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-10-11 19:25:23.183406
1513 1573,3,demo,43,bar,78.62.141.189,"push:cda1756acf28cae40e103db3792e4ac92c68d65a,3eab1e3601763da599d27541408fca1e12a09b02",2012-10-11 21:35:28.229244
1514 1574,3,demo,298,a-foo,"",started_following_repo,2012-10-12 15:29:23.1832
1515 1575,3,demo,298,a-foo,"",user_created_repo,2012-10-12 15:29:23.195979
1516 1576,3,demo,298,a-foo,"",stopped_following_repo,2012-10-12 15:30:16.975594
1517 1577,3,demo,298,a-foo,"",started_following_repo,2012-10-12 15:30:19.49313
1518 1578,3,demo,285,aloha,"",user_commented_revision:8411bc8656efd477e0c817ebbbf448fe5ca0d5fa,2012-10-12 16:04:13.119321
1519 1579,3,demo,299,test12345,"",started_following_repo,2012-10-13 02:45:09.148642
1520 1580,3,demo,299,test12345,"",user_created_repo,2012-10-13 02:45:09.15792
1521 1581,3,demo,300,TestTest,"",started_following_repo,2012-10-13 21:11:45.72971
1522 1582,3,demo,300,TestTest,"",user_created_repo,2012-10-13 21:11:45.738999
1523 1583,1,default,68,aaa-project,213.197.188.148,pull,2012-10-15 08:27:45.007378
1524 1584,3,demo,301,fork-glib,"",started_following_repo,2012-10-16 08:31:44.802094
1525 1585,3,demo,54,glib,"",user_forked_repo:fork-glib,2012-10-16 08:31:51.952999
1526 1586,3,demo,301,fork-glib,"",user_created_fork:fork-glib,2012-10-16 08:31:51.967931
1527 1587,3,demo,285,aloha,78.29.10.71,push:c7feb9671fc451e40758b9ed10496d854ba18a40,2012-10-16 08:34:12.115912
1528 1588,270,raoul1,302,TestRaoul,"",started_following_repo,2012-10-16 09:24:57.710057
1529 1589,270,raoul1,302,TestRaoul,"",user_created_repo,2012-10-16 09:24:57.725416
1530 1590,270,raoul1,302,TestRaoul,"",user_updated_repo,2012-10-16 09:25:13.334125
1531 1591,270,raoul1,302,TestRaoul,"",user_updated_repo,2012-10-16 09:27:33.159359
1532 1592,271,raoul2,302,TestRaoul,"",user_updated_repo,2012-10-16 09:30:24.581076
1533 1593,3,demo,68,aaa-project,"",user_commented_revision:0c33fa58efc5a5541d8d3f1a3d3b77367e3d94f5,2012-10-16 10:14:32.596831
1534 1594,272,jamesc,303,Magical-Cheese-Repo,"",started_following_repo,2012-10-16 12:10:35.216711
1535 1595,272,jamesc,303,Magical-Cheese-Repo,"",user_created_repo,2012-10-16 12:10:35.231231
1536 1596,272,jamesc,304,Cheese-Fork,"",started_following_repo,2012-10-16 12:11:16.231228
1537 1597,272,jamesc,303,Magical-Cheese-Repo,"",user_forked_repo:Cheese-Fork,2012-10-16 12:11:16.248472
1538 1598,272,jamesc,304,Cheese-Fork,"",user_created_fork:Cheese-Fork,2012-10-16 12:11:16.2598
1539 1599,272,jamesc,304,Cheese-Fork,"",push_local:47c7945748501f71737af1e83f5036cd17bde506,2012-10-16 12:13:20.106608
1540 1600,3,demo,,sproject,"",started_following_repo,2012-10-16 14:07:45.531949
1541 1601,3,demo,,sproject,"",user_created_repo,2012-10-16 14:07:45.550972
1542 1602,3,demo,,sproject,"",user_deleted_repo,2012-10-16 14:12:00.222929
1543 1603,3,demo,35,fork-Something22,"",user_updated_repo,2012-10-16 14:16:04.092997
1544 1604,3,demo,306,testflow,"",started_following_repo,2012-10-16 18:58:10.988582
1545 1605,3,demo,306,testflow,"",user_created_repo,2012-10-16 18:58:11.002092
1546 1665,3,demo,268,foofootest,"",user_updated_repo,2012-10-17 20:41:34.07778
1547 1666,1,default,266,fork-mercurial-trunk,78.53.4.31,pull,2012-10-18 00:34:23.822311
1548 1667,1,default,265,mercurial-trunk,78.53.4.31,pull,2012-10-18 00:35:14.549948
1549 1668,3,demo,34,a,"",push_local:a778c8853f594759661bf6e8fa9933dbd0c06390,2012-10-18 06:49:15.999219
1550 1669,3,demo,314,Test123654,"",started_following_repo,2012-10-18 09:13:40.498593
1551 1670,3,demo,314,Test123654,"",user_created_repo,2012-10-18 09:13:40.514075
1552 1671,3,demo,315,fork-a-foo,"",started_following_repo,2012-10-18 10:55:34.287082
1553 1672,3,demo,298,a-foo,"",user_forked_repo:fork-a-foo,2012-10-18 10:55:34.304187
1554 1673,3,demo,315,fork-a-foo,"",user_created_fork:fork-a-foo,2012-10-18 10:55:34.313058
1555 1674,279,sugia,316,Llskdjfsldkfjl,"",started_following_repo,2012-10-19 08:20:45.345545
1556 1675,279,sugia,316,Llskdjfsldkfjl,"",user_created_repo,2012-10-19 08:20:45.355759
1557 1676,279,sugia,316,Llskdjfsldkfjl,"",user_updated_repo,2012-10-19 08:21:47.944967
1558 1677,3,demo,317,foo-baz,"",started_following_repo,2012-10-19 14:14:29.057573
1559 1678,3,demo,317,foo-baz,"",user_created_repo,2012-10-19 14:14:29.070434
1560 1679,3,demo,38,code-review-test,"",user_commented_revision:6d7db5794e8cad7da042b6ae6238116c6e59a4d2,2012-10-19 16:10:33.532318
1561 1680,3,demo,249,abcdefg,"",user_commented_revision:ef6c825bc5699b95a31ae3075693b12693a623e2,2012-10-19 21:10:05.655859
1562 1681,3,demo,249,abcdefg,"",user_commented_revision:ef6c825bc5699b95a31ae3075693b12693a623e2,2012-10-19 21:10:17.138554
1563 1607,3,demo,306,testflow,69.36.131.254,"push:139bacf66d2ae74543bf01385d53434b5e619324,c9828e4c945cbbc0b98ebcb3633960a7495d6526",2012-10-16 20:15:52.423766
1564 1608,3,demo,307,zippo,"",started_following_repo,2012-10-16 21:57:00.837578
1565 1609,3,demo,307,zippo,"",user_created_repo,2012-10-16 21:57:00.852928
1566 1610,3,demo,307,zippo,"",user_updated_repo,2012-10-16 21:58:05.136205
1567 1611,3,demo,307,zippo,"",user_updated_repo,2012-10-16 21:58:17.135464
1568 1612,1,default,306,testflow,92.225.130.117,pull,2012-10-16 23:26:14.536761
1569 1613,3,demo,230,eks1,"",user_commented_revision:7be3eb971e236dd0c1d7b7c4637e7fab9c0a8eff,2012-10-17 10:01:12.801645
1570 1614,3,demo,230,eks1,"",user_commented_revision:7be3eb971e236dd0c1d7b7c4637e7fab9c0a8eff,2012-10-17 10:01:24.827945
1571 1615,3,demo,308,fork-abcdefg,"",started_following_repo,2012-10-17 10:46:38.608309
1572 1616,3,demo,249,abcdefg,"",user_forked_repo:fork-abcdefg,2012-10-17 10:46:38.625094
1573 1617,3,demo,308,fork-abcdefg,"",user_created_fork:fork-abcdefg,2012-10-17 10:46:38.636906
1574 1618,3,demo,308,fork-abcdefg,"",push_local:89b42b250956797b6bad5c7edbf873efe1b03d75,2012-10-17 10:47:28.606347
1575 1619,3,demo,249,abcdefg,"",user_commented_pull_request:69,2012-10-17 10:51:05.868185
1576 1620,2,admin,249,abcdefg,"",user_commented_pull_request:69,2012-10-17 15:34:01.14742
1577 1621,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:125ff5654b72009b251706d7ee93051853f066b6,2012-10-17 15:36:37.784768
1578 1622,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:125ff5654b72009b251706d7ee93051853f066b6,2012-10-17 15:37:36.599064
1579 1623,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:125ff5654b72009b251706d7ee93051853f066b6,2012-10-17 15:38:14.176552
1580 1624,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:125ff5654b72009b251706d7ee93051853f066b6,2012-10-17 15:38:41.016672
1581 1625,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:1bd18c415eec578b5a8cc3bb61c65e554f4674e1,2012-10-17 15:39:31.815756
1582 1626,276,niels,309,fork-bla,"",started_following_repo,2012-10-17 16:14:16.700471
1583 1627,276,niels,278,bla,"",user_forked_repo:fork-bla,2012-10-17 16:14:16.804166
1584 1628,276,niels,309,fork-bla,"",user_created_fork:fork-bla,2012-10-17 16:14:16.818566
1585 1629,3,demo,249,abcdefg,"",user_commented_pull_request:69,2012-10-17 16:21:09.732638
1586 1630,3,demo,249,abcdefg,"",user_closed_pull_request:69,2012-10-17 16:21:09.743958
1587 1631,3,demo,310,ForkMe,"",started_following_repo,2012-10-17 16:39:43.040558
1588 1632,3,demo,310,ForkMe,"",user_created_repo,2012-10-17 16:39:43.051548
1589 1633,3,demo,310,ForkMe,20.132.68.148,"push:20867b19ea55d7afa34238c5b42e8f0cf9336fb9,57b41cfbab38011c7d95d929afe8c54d41d229c7,c473af323363c2ce57b1dd3baaf671eabbbe3d9b,11d5db13f3886df26fa9052d664dd99c7ad7a32f,d7d1bb376a19e46ce927520f6863c286aae3d118,160f86cca435674ce9fbd7fb34a7eb1684cd753e,44d8bad99c89ba30af51c0fb96d0c4f5ff679b67,12253658153cfdcab846f64b91f13f56631abae1,ec85db68de4419c2cdaa9e9a4c0cd0a12e161c9e,98e055683c7acd57b6393fffb5bc9ef7fd8386aa,9fd9140573cfccdb795905c962d515fd199024a1",2012-10-17 16:40:52.585834
1590 1634,3,demo,311,ForkForForkMe,"",started_following_repo,2012-10-17 16:41:54.089171
1591 1635,3,demo,310,ForkMe,"",user_forked_repo:ForkForForkMe,2012-10-17 16:41:54.105915
1592 1636,3,demo,311,ForkForForkMe,"",user_created_fork:ForkForForkMe,2012-10-17 16:41:54.119943
1593 1637,1,default,311,ForkForForkMe,20.132.68.148,pull,2012-10-17 16:42:50.019391
1594 1638,3,demo,311,ForkForForkMe,20.132.68.148,push:7f7a317f656658d18438fa4f2effca0cfe1bee77,2012-10-17 16:43:30.115193
1595 1639,3,demo,310,ForkMe,"",user_commented_pull_request:70,2012-10-17 16:45:19.643124
1596 1640,3,demo,310,ForkMe,"",user_closed_pull_request:70,2012-10-17 16:45:19.651818
1597 1641,1,default,310,ForkMe,20.132.68.148,pull,2012-10-17 16:55:41.290306
1598 1642,1,default,311,ForkForForkMe,20.132.68.148,pull,2012-10-17 17:01:31.007755
1599 1643,1,default,310,ForkMe,20.132.68.148,pull,2012-10-17 17:02:42.098164
1600 1644,1,default,311,ForkForForkMe,20.132.68.148,pull,2012-10-17 17:05:59.739608
1601 1645,3,demo,311,ForkForForkMe,20.132.68.148,"push:3ebc10c9b1ea1d26ff9ede63104d6ab24bf6d37d,e2687070a7d4092aafde9343ad79c57c39ec016f",2012-10-17 17:17:21.346216
1602 1646,1,default,310,ForkMe,20.132.68.148,pull,2012-10-17 17:17:56.010058
1603 1647,3,demo,312,pepepe,"",started_following_repo,2012-10-17 17:20:14.076678
1604 1648,3,demo,312,pepepe,"",user_created_repo,2012-10-17 17:20:14.089715
1605 1649,3,demo,311,ForkForForkMe,20.132.68.148,"push:37298d3eed24e9209bfaf5b43bda114b28d99363,1dc8b7b3029c583069aa80ebc5b570c11cea998b",2012-10-17 17:20:19.128212
1606 1650,3,demo,312,pepepe,"",push_local:72fc0eb74ecaffd64c3594744f8ad0634f68ab2b,2012-10-17 17:20:35.135261
1607 1651,3,demo,312,pepepe,"",user_commented_revision:72fc0eb74ecaffd64c3594744f8ad0634f68ab2b,2012-10-17 17:20:53.662433
1608 1652,3,demo,313,fork-pepepe,"",started_following_repo,2012-10-17 17:21:29.352267
1609 1653,3,demo,312,pepepe,"",user_forked_repo:fork-pepepe,2012-10-17 17:21:29.36938
1610 1654,3,demo,313,fork-pepepe,"",user_created_fork:fork-pepepe,2012-10-17 17:21:29.382134
1611 1655,3,demo,313,fork-pepepe,"",push_local:d96f66d613e7c90004b0be702fa00acb5c64d22b,2012-10-17 17:22:27.210919
1612 1656,1,default,311,ForkForForkMe,20.132.68.148,pull,2012-10-17 17:22:51.855061
1613 1657,3,demo,312,pepepe,"",user_commented_pull_request:71,2012-10-17 17:23:15.633271
1614 1658,3,demo,312,pepepe,"",user_closed_pull_request:71,2012-10-17 17:23:15.639775
1615 1659,1,default,310,ForkMe,20.132.68.148,pull,2012-10-17 19:44:37.643519
1616 1660,1,default,311,ForkForForkMe,20.132.68.148,pull,2012-10-17 19:49:02.152121
1617 1661,1,default,311,ForkForForkMe,20.132.68.148,pull,2012-10-17 19:51:33.051372
1618 1662,1,default,310,ForkMe,20.132.68.148,pull,2012-10-17 20:02:23.092402
1619 1663,1,default,311,ForkForForkMe,20.132.68.148,pull,2012-10-17 20:21:12.146576
1620 1664,3,demo,269,fork-foofootest,"",user_updated_repo,2012-10-17 20:39:09.557172
1621 1682,3,demo,249,abcdefg,"",user_commented_revision:5d80e28538141e322b317168e2367fb03178d58c,2012-10-19 21:11:07.868323
1622 1683,280,SylvainC,318,testrcd99,"",started_following_repo,2012-10-19 22:52:25.55997
1623 1684,280,SylvainC,318,testrcd99,"",user_created_repo,2012-10-19 22:52:25.572046
1624 1685,281,coderazor,38,code-review-test,"",user_commented_pull_request:65,2012-10-19 23:15:14.542145
1625 1686,281,coderazor,38,code-review-test,"",user_commented_pull_request:65,2012-10-19 23:16:01.295617
1626 1687,281,coderazor,38,code-review-test,"",user_commented_pull_request:65,2012-10-19 23:20:08.509514
1627 1688,281,coderazor,319,fork1-code-review-test,"",started_following_repo,2012-10-20 00:46:43.404342
1628 1689,281,coderazor,38,code-review-test,"",user_forked_repo:fork1-code-review-test,2012-10-20 00:46:43.464675
1629 1690,281,coderazor,319,fork1-code-review-test,"",user_created_fork:fork1-code-review-test,2012-10-20 00:46:43.473779
1630 1691,281,coderazor,319,fork1-code-review-test,"",push_local:98690895f701c1827ea962fe81985b6094a3f00e,2012-10-20 00:48:45.66637
1631 1692,281,coderazor,319,fork1-code-review-test,"",push_local:b364947ef413a4b2f43bb76ba221d47c1794a8e1,2012-10-20 00:49:40.078971
1632 1693,281,coderazor,319,fork1-code-review-test,"",user_commented_revision:b364947ef413a4b2f43bb76ba221d47c1794a8e1,2012-10-20 00:50:35.035023
1633 1694,281,coderazor,38,code-review-test,"",user_commented_pull_request:72,2012-10-20 00:54:57.701596
1634 1695,281,coderazor,38,code-review-test,"",user_commented_pull_request:72,2012-10-20 00:55:44.681278
1635 1696,281,coderazor,38,code-review-test,"",user_commented_pull_request:72,2012-10-20 00:55:59.492315
1636 1697,281,coderazor,319,fork1-code-review-test,"",push_local:e216971a777e3132487405dd2c8e093f66788765,2012-10-20 00:59:53.583102
1637 1698,281,coderazor,38,code-review-test,"",user_commented_pull_request:72,2012-10-20 01:01:16.602261
1638 1699,281,coderazor,38,code-review-test,"",user_commented_pull_request:72,2012-10-20 01:03:46.692176
1639 1700,281,coderazor,38,code-review-test,"",user_commented_pull_request:73,2012-10-20 01:06:18.310904
1640 1701,281,coderazor,38,code-review-test,"",user_commented_pull_request:72,2012-10-20 01:07:52.891399
1641 1702,281,coderazor,38,code-review-test,"",user_closed_pull_request:72,2012-10-20 01:07:52.900684
1642 1703,283,vaidasn,320,svn2git.git,"",started_following_repo,2012-10-20 19:40:57.345453
1643 1704,283,vaidasn,320,svn2git.git,"",user_created_repo,2012-10-20 19:40:57.365761
1644 1705,3,demo,321,Mecurial-Test,"",started_following_repo,2012-10-22 06:13:45.980502
1645 1706,3,demo,321,Mecurial-Test,"",user_created_repo,2012-10-22 06:13:45.997596
1646 1707,3,demo,321,Mecurial-Test,69.196.152.196,push:e66dfe4e33871da460d3807c8b015863bf7240b7,2012-10-22 06:54:33.247493
1647 1708,3,demo,321,Mecurial-Test,"",user_updated_repo,2012-10-22 06:56:19.772283
1648 1709,3,demo,321,Mecurial-Test,69.196.152.196,push:eee6785689defc10df9fe6e8d0921facaab0e176,2012-10-22 07:08:00.585766
1649 1710,3,demo,321,Mecurial-Test,69.196.152.196,push:fd10c02cfbfbf4a7d7659c67998c6f95da5dc4de,2012-10-22 07:10:59.095472
1650 1711,254,yujiro,322,fork-code-review-dev,"",started_following_repo,2012-10-22 10:01:47.558754
1651 1712,254,yujiro,173,code-review-dev,"",user_forked_repo:fork-code-review-dev,2012-10-22 10:01:47.58102
1652 1713,254,yujiro,322,fork-code-review-dev,"",user_created_fork:fork-code-review-dev,2012-10-22 10:01:47.59189
1653 1714,285,zza,323,TestZZa,"",started_following_repo,2012-10-22 11:36:34.479105
1654 1715,285,zza,323,TestZZa,"",user_created_repo,2012-10-22 11:36:34.488683
1655 1716,285,zza,323,TestZZa,"",user_updated_repo,2012-10-22 11:37:27.008002
1656 1717,285,zza,323,TestZZa,"",user_updated_repo,2012-10-22 11:37:40.09398
1657 1718,3,demo,285,aloha,"",push_local:f6aea433e6b6cb05d4af9ac74bac0da5fd09c8ba,2012-10-22 12:50:54.991895
1658 1719,1,default,321,Mecurial-Test,67.70.161.159,pull,2012-10-22 15:41:30.593105
1659 1720,3,demo,321,Mecurial-Test,67.70.161.159,push:041e48fd7acad4c27385c27a4789d3d5cc7ccbea,2012-10-22 16:39:38.382409
1660 1721,1,default,321,Mecurial-Test,69.196.152.196,pull,2012-10-22 23:13:11.713227
1661 1722,3,demo,325,testkyro,"",started_following_repo,2012-10-23 13:27:46.011096
1662 1723,3,demo,325,testkyro,"",user_created_repo,2012-10-23 13:27:46.024014
1663 1724,3,demo,325,testkyro,"",user_updated_repo,2012-10-23 13:28:29.072813
1664 1725,3,demo,326,ReallyCoolProject,"",started_following_repo,2012-10-23 14:22:15.477077
1665 1726,3,demo,326,ReallyCoolProject,"",user_created_repo,2012-10-23 14:22:15.492068
1666 1727,3,demo,326,ReallyCoolProject,"",push_local:262220ea2a60e92577f2193cd9ee4f9707760fb5,2012-10-23 14:23:56.826353
1667 1728,288,kiall,327,kiall-test,"",started_following_repo,2012-10-23 15:50:27.397495
1668 1729,288,kiall,327,kiall-test,"",user_created_repo,2012-10-23 15:50:27.42126
1669 1730,288,kiall,329,fork-aaa-projects,"",started_following_repo,2012-10-23 15:53:23.020591
1670 1731,288,kiall,68,aaa-project,"",user_forked_repo:fork-aaa-projects,2012-10-23 15:53:23.043059
1671 1732,288,kiall,329,fork-aaa-projects,"",user_created_fork:fork-aaa-projects,2012-10-23 15:53:23.052289
1672 1733,288,kiall,328,kiall-nova,"",started_following_repo,2012-10-23 15:53:45.417443
1673 1734,288,kiall,328,kiall-nova,"",user_created_repo,2012-10-23 15:53:45.434684
1674 1735,288,kiall,329,fork-aaa-projects,"",push_local:417cac332ab3512a08d5454cfcbffc21471e1f6f,2012-10-23 15:53:50.165591
1675 1736,3,demo,330,z123,"",started_following_repo,2012-10-23 15:58:30.652495
1676 1737,3,demo,330,z123,"",user_created_repo,2012-10-23 15:58:30.665854
1677 1738,3,demo,330,z123,"",push_local:0ba461ee4cd15d51f416b1073d4389574150f5ca,2012-10-23 15:59:26.238194
1678 1739,3,demo,330,z123,"",user_updated_repo,2012-10-23 16:01:08.667715
1679 1740,288,kiall,331,kiall-hg,"",started_following_repo,2012-10-23 16:01:24.811434
1680 1741,288,kiall,331,kiall-hg,"",user_created_repo,2012-10-23 16:01:24.820628
1681 1742,1,default,330,z123,80.149.98.186,pull,2012-10-23 16:02:35.273406
1682 1743,3,demo,330,z123,80.149.98.186,push:b89e8c4620b21ec38d159c644b173a1c93efafea,2012-10-23 16:04:08.66449
1683 1744,3,demo,330,z123,"",user_commented_revision:b89e8c4620b21ec38d159c644b173a1c93efafea,2012-10-23 16:04:55.372793
1684 1745,2,admin,,"","",admin_updated_user:kiall,2012-10-23 16:05:04.180487
1685 1746,3,demo,330,z123,"",stopped_following_repo,2012-10-23 16:16:39.414967
1686 1747,3,demo,34,a,"",push_local:106ab79178979f8e464e5cc8f432347f8c203dde,2012-10-23 16:24:17.669006
1687 1748,3,demo,332,IAmTesting-this,"",started_following_repo,2012-10-23 18:51:16.88748
1688 1749,3,demo,332,IAmTesting-this,"",user_created_repo,2012-10-23 18:51:16.902186
1689 1750,3,demo,333,IAmTesting_this,"",started_following_repo,2012-10-23 19:15:24.347861
1690 1751,3,demo,333,IAmTesting_this,"",user_created_repo,2012-10-23 19:15:24.361363
1691 1752,3,demo,333,IAmTesting_this,"",user_updated_repo,2012-10-23 19:35:36.723229
1692 1753,1,default,333,IAmTesting_this,194.117.18.103,push:31ca1f206de23b0d257dcbb323f9ba94e142ceb5,2012-10-23 19:59:07.360826
1693 1754,3,demo,334,Test1qwerty,"",started_following_repo,2012-10-23 20:56:13.001385
1694 1755,3,demo,334,Test1qwerty,"",user_created_repo,2012-10-23 20:56:13.014633
1695 1756,3,demo,334,Test1qwerty,"",push_local:5957aa6f6f14241663b8b1a0ca050e43c3d3ca27,2012-10-23 20:57:25.88513
1696 1757,3,demo,335,git,"",started_following_repo,2012-10-23 21:49:35.974797
1697 1758,3,demo,335,git,"",user_created_repo,2012-10-23 21:49:35.994798
1698 1759,3,demo,336,fork-cruel-test-2,"",started_following_repo,2012-10-23 23:49:23.770508
1699 1760,3,demo,174,releases/cruel-test-2,"",user_forked_repo:fork-cruel-test-2,2012-10-23 23:49:23.85229
1700 1761,3,demo,336,fork-cruel-test-2,"",user_created_fork:fork-cruel-test-2,2012-10-23 23:49:23.867582
1701 1762,3,demo,337,why-testing,"",started_following_repo,2012-10-23 23:53:03.878941
1702 1763,3,demo,337,why-testing,"",user_created_repo,2012-10-23 23:53:03.893321
1703 1764,3,demo,338,temp11,"",started_following_repo,2012-10-24 10:43:46.379754
1704 1765,3,demo,338,temp11,"",user_created_repo,2012-10-24 10:43:46.391127
1705 1766,3,demo,339,test123,"",started_following_repo,2012-10-24 14:10:41.927001
1706 1767,3,demo,339,test123,"",user_created_repo,2012-10-24 14:10:41.936239
1707 1768,3,demo,339,releases/test123,"",user_updated_repo,2012-10-24 14:10:57.739304
1708 1769,2,admin,339,releases/test123,146.48.87.66,push:87e9dcd8d3e375c218fdb747da52dc1551a93dc7,2012-10-24 14:12:02.63513
1709 1770,292,Airframe,340,Testtestac,"",started_following_repo,2012-10-24 17:09:26.37836
1710 1771,292,Airframe,340,Testtestac,"",user_created_repo,2012-10-24 17:09:26.387917
1711 1772,293,imbehind,190,rhodecode,"",user_commented_revision:008d9c6f7c92636aaeda6f182bffecac6a464dd3,2012-10-24 20:38:59.535098
1712 1773,3,demo,341,MicTest,"",started_following_repo,2012-10-24 20:59:34.176289
1713 1774,3,demo,341,MicTest,"",user_created_repo,2012-10-24 20:59:34.186308
1714 1775,3,demo,341,MicTest,"",push_local:327bf84d0d633a66f0c7ff4533de2415c9ff5a88,2012-10-24 21:00:28.379598
1715 1776,295,mhassanzadeh,342,ttest,"",started_following_repo,2012-10-25 10:50:06.001658
1716 1777,295,mhassanzadeh,342,ttest,"",user_created_repo,2012-10-25 10:50:06.011192
1717 1807,306,foobar,,foobar,"",user_forked_repo:fork-foobar,2012-10-30 05:39:47.942232
1718 1809,306,foobar,,foobar,24.67.50.255,push:0e3a7dcdd90bdb2a1f6dbe85e7b574e4f6304207,2012-10-30 05:50:43.083487
1719 1781,3,demo,,fork-rawr,"",user_deleted_repo,2012-10-25 15:14:56.164313
1720 1782,3,demo,343,test_git_repo,"",started_following_repo,2012-10-26 13:31:41.642802
1721 1783,3,demo,343,test_git_repo,"",user_created_repo,2012-10-26 13:31:41.653854
1722 1784,2,admin,99,another-fork-to-check-code-review,"",user_commented_revision:d5422faf648cc589425cd3b0dbf1f6dbf93036a0,2012-10-27 15:38:54.924143
1723 1785,3,demo,344,sadfasdf,"",started_following_repo,2012-10-28 11:41:22.491275
1724 1786,3,demo,344,sadfasdf,"",user_created_repo,2012-10-28 11:41:22.503388
1725 1787,3,demo,345,fork-dvorak,"",started_following_repo,2012-10-29 09:43:08.276759
1726 1788,3,demo,129,dvorak,"",user_forked_repo:fork-dvorak,2012-10-29 09:43:08.321733
1727 1789,3,demo,345,fork-dvorak,"",user_created_fork:fork-dvorak,2012-10-29 09:43:08.329436
1728 1790,3,demo,346,my-test-repo,"",started_following_repo,2012-10-29 09:45:29.684135
1729 1791,3,demo,346,my-test-repo,"",user_created_repo,2012-10-29 09:45:29.694219
1730 1792,3,demo,347,fork-aaa-project111,"",started_following_repo,2012-10-29 09:50:58.797507
1731 1793,3,demo,68,aaa-project,"",user_forked_repo:fork-aaa-project111,2012-10-29 09:50:58.809098
1732 1794,3,demo,347,fork-aaa-project111,"",user_created_fork:fork-aaa-project111,2012-10-29 09:50:58.816283
1733 1795,2,admin,348,group/I-am-a-very-long-repository-name,"",started_following_repo,2012-10-29 15:51:18.519038
1734 1796,2,admin,348,group/I-am-a-very-long-repository-name,"",admin_created_repo,2012-10-29 15:51:18.528651
1735 1797,3,demo,34,a-very-long-usper-loooong-name-that-is-to-long,"",user_updated_repo,2012-10-29 17:32:06.365281
1736 1798,3,demo,350,misisko-repo,"",started_following_repo,2012-10-29 20:19:56.180975
1737 1799,3,demo,350,misisko-repo,"",user_created_repo,2012-10-29 20:19:56.190032
1738 1800,3,demo,350,misisko-repo,195.168.239.153,push:34bd2e2b6cf2abdb0e026182b9342f95d8f6f440,2012-10-29 20:21:33.067763
1739 1801,3,demo,350,misisko-repo,"",user_commented_revision:34bd2e2b6cf2abdb0e026182b9342f95d8f6f440,2012-10-29 20:23:32.816207
1740 1802,2,admin,350,misisko-repo,"",push_local:89a041cce422153ba0716a2beb2b5711ee4f4280,2012-10-29 21:23:56.649892
1741 1806,306,foobar,,fork-foobar,"",started_following_repo,2012-10-30 05:39:47.86196
1742 1808,306,foobar,,fork-foobar,"",user_created_fork:fork-foobar,2012-10-30 05:39:47.956653
1743 1811,306,foobar,,fork-foobar,"",user_deleted_repo,2012-10-30 05:56:06.059093
1744 1803,306,foobar,,foobar,"",started_following_repo,2012-10-30 05:36:49.915108
1745 1804,306,foobar,,foobar,"",user_created_repo,2012-10-30 05:36:49.929097
1746 1805,306,foobar,,foobar,24.67.50.255,push:3b0ad3c9b89dec8bcac5ec8bc9846f307dd5f291,2012-10-30 05:38:30.960676
1747 1810,306,foobar,,foobar,24.67.50.255,push:5066e223f81d3983b9bc4d959c509bbce326474c,2012-10-30 05:53:14.168715
1748 1812,306,foobar,,foobar,"",user_deleted_repo,2012-10-30 05:56:35.211293
1749 1813,3,demo,354,DibaDaba,"",started_following_repo,2012-10-30 10:55:03.068862
1750 1814,3,demo,354,DibaDaba,"",user_created_repo,2012-10-30 10:55:03.088077
1751 1815,3,demo,354,DibaDaba,"",push_local:cf41636a602d2a69128cc58fdf441857afb83827,2012-10-30 10:56:16.451197
1752 1816,3,demo,354,DibaDaba,"",user_updated_repo,2012-10-30 11:05:50.836108
1753 1817,3,demo,354,DibaDaba,"",push_local:15453a2035510dcefbc8b7f3e45b916003ae4a0f,2012-10-30 11:18:42.79919
1754 1818,3,demo,355,Test-RohdeCode,"",started_following_repo,2012-10-30 21:07:27.016976
1755 1819,3,demo,355,Test-RohdeCode,"",user_created_repo,2012-10-30 21:07:27.040381
1756 1820,3,demo,355,Test-RohdeCode,"",push_local:a2c7c944a5bae039181a84bec8bc89a9bb4ac68c,2012-10-31 10:52:21.038578
1757 1821,3,demo,355,Test-RohdeCode,"",push_local:303c0051c7a04b5a4f77654d8cfeb09a61322e15,2012-10-31 16:32:16.917289
1758 1822,3,demo,356,testdzone,"",started_following_repo,2012-11-02 15:51:18.982652
1759 1823,3,demo,356,testdzone,"",user_created_repo,2012-11-02 15:51:18.994144
1760 1824,3,demo,357,firs,"",started_following_repo,2012-11-04 00:37:08.689703
1761 1825,3,demo,357,firs,"",user_created_repo,2012-11-04 00:37:08.700977
1762 1826,316,theo,358,brightandshiny,"",started_following_repo,2012-11-04 14:17:04.270938
1763 1827,316,theo,358,brightandshiny,"",user_created_repo,2012-11-04 14:17:04.286049
1764 1828,316,theo,358,brightandshiny,87.165.13.203,"push:831fd48093c38f64bb541a4c12bec45d27c13f9d,0177264991ad113c2dbeed00716738931bc0222f",2012-11-04 14:21:33.759458
1765 1829,3,demo,45,group/fork-bootstrap,"",started_following_repo,2012-11-04 18:25:45.459487
1766 1830,3,demo,45,group/fork-bootstrap,"",stopped_following_repo,2012-11-04 18:25:48.166886
1767 1831,3,demo,45,group/fork-bootstrap,"",started_following_repo,2012-11-04 18:25:51.905362
1768 1832,3,demo,45,group/fork-bootstrap,"",stopped_following_repo,2012-11-04 18:25:54.406445
1769 1833,3,demo,227,fork-aaa-project-2,"",user_commented_revision:bc829c34912709c7d129e5dae9a3e5ff46e77fc7,2012-11-05 18:37:48.772572
1770 1834,3,demo,227,fork-aaa-project-2,"",user_commented_revision:bc829c34912709c7d129e5dae9a3e5ff46e77fc7,2012-11-05 18:38:42.521316
1771 1835,3,demo,359,MyUberRepo,"",started_following_repo,2012-11-05 22:04:02.939575
1772 1836,3,demo,359,MyUberRepo,"",user_created_repo,2012-11-05 22:04:02.95609
1773 1837,3,demo,359,MyUberRepo,"",push_local:a67ddbdca6d533e0cd43175068cc12f526b2f95f,2012-11-05 22:07:40.846096
1774 1838,3,demo,360,marese_test,"",started_following_repo,2012-11-05 22:10:35.535744
1775 1839,3,demo,360,marese_test,"",user_created_repo,2012-11-05 22:10:35.547878
1776 1840,3,demo,361,test-23,"",started_following_repo,2012-11-06 04:01:46.385817
1777 1841,3,demo,361,test-23,"",user_created_repo,2012-11-06 04:01:46.410423
1778 1842,3,demo,361,test-23,"",push_local:7d8547b154a01c7055a09292e871e80f3c6b574b,2012-11-06 04:03:03.320736
1779 1843,3,demo,361,test-23,"",user_commented_revision:7d8547b154a01c7055a09292e871e80f3c6b574b,2012-11-06 04:07:20.51212
1780 1844,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-11-06 04:12:51.753053
1781 1845,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-11-06 04:13:30.727101
1782 1846,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:fba17a64fa4978bfea19222da5e64a18cfddeecd,2012-11-06 04:15:29.032768
1783 1847,3,demo,68,aaa-project,"",user_commented_revision:0c33fa58efc5a5541d8d3f1a3d3b77367e3d94f5,2012-11-06 04:17:16.091927
1784 1848,3,demo,249,abcdefg,"",user_commented_revision:5d80e28538141e322b317168e2367fb03178d58c,2012-11-06 06:10:53.372505
1785 1849,3,demo,362,Marcin,"",started_following_repo,2012-11-06 10:45:38.505485
1786 1850,3,demo,362,Marcin,"",user_created_repo,2012-11-06 10:45:38.518969
1787 1851,3,demo,362,hidden/Marcin,"",user_updated_repo,2012-11-06 10:45:46.281581
1788 1852,3,demo,177,blah,62.200.22.2,push:b369fb18c8d61fe0d3b14c417466680230cabe46,2012-11-06 10:47:55.655029
1789 1853,3,demo,99,another-fork-to-check-code-review,"",user_commented_revision:d5422faf648cc589425cd3b0dbf1f6dbf93036a0,2012-11-06 13:12:05.517155
1790 1854,3,demo,38,code-review-test,"",user_commented_revision:6d7db5794e8cad7da042b6ae6238116c6e59a4d2,2012-11-06 16:12:59.38977
1791 1855,3,demo,363,utf8-test,"",started_following_repo,2012-11-06 16:52:34.020264
1792 1856,3,demo,363,utf8-test,"",user_created_repo,2012-11-06 16:52:34.036171
1793 1857,3,demo,363,utf8-test,178.6.80.143,push:e9e69068b8277c8e857984fb44e54d4e057710bd,2012-11-06 16:54:30.357337
1794 1858,320,blahblub,364,abc_test,"",started_following_repo,2012-11-06 22:06:45.476725
1795 1859,320,blahblub,364,abc_test,"",user_created_repo,2012-11-06 22:06:45.488546
1796 1860,320,blahblub,364,abc_test,81.190.220.154,"push:e05d82d631f4a61972c2c76eb5b473c55ee6133f,dccf54ebc0638183872cfd9d35f0f49aa44ad4bc",2012-11-06 22:07:39.657839
1797 1861,320,blahblub,364,abc_test,81.190.220.154,push:8ef2f06b68eb25067c4ca3a9c73c89bb681f031b,2012-11-06 22:09:18.572762
1798 1862,3,demo,365,testing_do,"",started_following_repo,2012-11-07 00:19:56.15291
1799 1863,3,demo,365,testing_do,"",user_created_repo,2012-11-07 00:19:56.165626
1800 1864,3,demo,365,testing_do,"",user_updated_repo,2012-11-07 00:21:24.482025
1801 1865,3,demo,321,Mecurial-Test,"",user_commented_revision:041e48fd7acad4c27385c27a4789d3d5cc7ccbea,2012-11-07 01:16:37.129361
1802 1866,321,ifco89,284,fork-django,"",user_commented_revision:129f1ac8484d63c2e61a44fb2a18dd17246c1c4d,2012-11-07 01:26:40.887017
1803 1867,3,demo,284,fork-django,"",user_commented_revision:c5d6f6d6829e730bdddf63c1252304f0c49a9053,2012-11-07 01:27:33.995596
1804 1868,3,demo,68,aaa-project,"",push_local:5ecd97456233badb3680873dc5b7d4bfb52ede79,2012-11-07 06:43:22.378406
1805 1869,3,demo,319,fork1-code-review-test,"",user_commented_revision:e216971a777e3132487405dd2c8e093f66788765,2012-11-07 08:44:19.419642
1806 1870,3,demo,366,test123123,"",started_following_repo,2012-11-07 14:16:13.029479
1807 1871,3,demo,366,test123123,"",user_created_repo,2012-11-07 14:16:13.04346
1808 1872,323,didi,364,abc_test,"",user_commented_revision:8ef2f06b68eb25067c4ca3a9c73c89bb681f031b,2012-11-07 15:45:10.378961
1809 1873,324,tutty,367,fork-bootstrap,"",started_following_repo,2012-11-07 16:00:47.116111
1810 1874,324,tutty,36,bootstrap,"",user_forked_repo:fork-bootstrap,2012-11-07 16:00:48.378051
1811 1875,324,tutty,367,fork-bootstrap,"",user_created_fork:fork-bootstrap,2012-11-07 16:00:48.393002
1812 1876,3,demo,68,aaa-project,"",user_commented_revision:b4bf1f77b1288a24eb395537319b4f3155cffa71,2012-11-08 18:41:07.016059
1813 1877,3,demo,68,aaa-project,"",user_commented_revision:b4bf1f77b1288a24eb395537319b4f3155cffa71,2012-11-08 18:41:34.311311
1814 1878,3,demo,68,aaa-project,"",user_commented_revision:b4bf1f77b1288a24eb395537319b4f3155cffa71,2012-11-08 18:41:38.071834
1815 1879,3,demo,368,Repotest,"",started_following_repo,2012-11-09 10:40:40.804085
1816 1880,3,demo,368,Repotest,"",user_created_repo,2012-11-09 10:40:40.813114
1817 1881,3,demo,369,fork-HelloWorld,"",started_following_repo,2012-11-10 19:57:46.238558
1818 1882,3,demo,280,HelloWorld,"",user_forked_repo:fork-HelloWorld,2012-11-10 19:57:46.306001
1819 1883,3,demo,369,fork-HelloWorld,"",user_created_fork:fork-HelloWorld,2012-11-10 19:57:46.320675
1820 1884,3,demo,370,fork-django-more,"",started_following_repo,2012-11-11 01:18:51.709667
1821 1885,3,demo,110,django,"",user_forked_repo:fork-django-more,2012-11-11 01:18:58.716934
1822 1886,3,demo,370,fork-django-more,"",user_created_fork:fork-django-more,2012-11-11 01:18:58.731127
1823 1887,3,demo,371,hgh,"",started_following_repo,2012-11-12 06:07:06.509759
1824 1888,3,demo,371,hgh,"",user_created_repo,2012-11-12 06:07:06.525795
1825 1889,3,demo,371,hgh,"",push_local:b43f437976ff61a8fa37709f105091ffd00bbd2c,2012-11-12 06:08:34.009007
1826 1890,3,demo,371,hgh,"",push_local:93c5a23d3cbde4c6dbd21d722eb1beff90a1d67c,2012-11-12 06:09:44.749181
1827 1891,3,demo,371,hgh,"",push_local:d3e97cf131b0feaa586272d88e71e97a65564806,2012-11-12 06:13:04.240444
1828 1892,336,demodemo,373,test-for,"",started_following_repo,2012-11-12 18:29:12.02868
1829 1893,336,demodemo,373,test-for,"",user_created_repo,2012-11-12 18:29:12.041121
1830 1894,336,demodemo,374,fork-test-for,"",started_following_repo,2012-11-12 18:29:25.869055
1831 1895,336,demodemo,373,test-for,"",user_forked_repo:fork-test-for,2012-11-12 18:29:25.922561
1832 1896,336,demodemo,374,fork-test-for,"",user_created_fork:fork-test-for,2012-11-12 18:29:25.936869
1833 1897,336,demodemo,374,fork-test-for,101.140.96.42,push:a7495b86f0bfc299740cdbfbbca1b9d5ca1f62de,2012-11-12 18:31:51.107494
1834 1898,2,admin,376,linux-kernel,"",started_following_repo,2012-11-13 22:14:17.466937
1835 1899,342,gauravve,377,myrep,"",started_following_repo,2012-11-14 12:12:46.280751
1836 1900,342,gauravve,377,myrep,"",user_created_repo,2012-11-14 12:12:46.296606
1837 1901,343,yasser.a,125,test-to-end-all-tests,"",user_commented_revision:fb4eb182028a674ae250430c04305e9b3fbe508e,2012-11-14 16:17:28.970017
1838 772,2,admin,,cruel-test,"",started_following_repo,2012-08-28 10:23:44.560576
1839 1902,254,yujiro,378,arai-new-repo,"",started_following_repo,2012-11-15 02:39:50.649631
1840 1903,254,yujiro,378,arai-new-repo,"",user_created_repo,2012-11-15 02:39:50.667177
1841 1904,254,yujiro,378,arai-new-repo,182.171.245.184,push:6beb6da3b0e27eb1401090e122f7675d56e07fc1,2012-11-15 02:45:25.207338
1842 1905,3,demo,381,test01012145,"",started_following_repo,2012-11-16 13:02:38.980282
1843 1906,3,demo,381,test01012145,"",user_created_repo,2012-11-16 13:02:38.989119
1844 1907,3,demo,381,test01012145,"",push_local:225a9898957de5f78ac2aa8e4d46a80eed3ee6d5,2012-11-16 13:04:53.384353
1845 1908,3,demo,382,aaa-repo-fork,"",started_following_repo,2012-11-17 12:58:42.919876
1846 1909,3,demo,67,group/aaa-repo,"",user_forked_repo:aaa-repo-fork,2012-11-17 12:58:42.981111
1847 1910,3,demo,382,aaa-repo-fork,"",user_created_fork:aaa-repo-fork,2012-11-17 12:58:42.992071
1848 1911,3,demo,382,aaa-repo-fork,"",user_updated_repo,2012-11-17 12:59:32.084662
1849 1912,2,admin,,"","",admin_updated_user:kiall,2012-11-17 21:52:15.776253
1850 1913,3,demo,268,foofootest,"",user_commented_revision:4bc0645c20363db85c9a5050a85c2c05a1991765,2012-11-20 12:19:44.614295
1851 1914,3,demo,383,aaa-test-repo,"",started_following_repo,2012-11-20 12:27:16.120325
1852 1915,3,demo,383,aaa-test-repo,"",user_created_repo,2012-11-20 12:27:16.130553
1853 1916,3,demo,383,aaa-test-repo,"",push_local:fb2f5ae9a806abe4cb03fe7b11d4ad21a836f7b6,2012-11-20 12:27:41.98988
1854 1917,3,demo,384,aaa-test-repo2,"",started_following_repo,2012-11-20 12:31:43.009679
1855 1918,3,demo,384,aaa-test-repo2,"",user_created_repo,2012-11-20 12:31:43.019015
1856 1919,3,demo,384,aaa-test-repo2,"",push_local:83a7be8f9d651912ee343067bd392678fbebe3e8,2012-11-20 12:32:34.336741
1857 1920,3,demo,385,aaa-test-repo2-fork,"",started_following_repo,2012-11-20 12:58:25.715274
1858 1921,3,demo,384,aaa-test-repo2,"",user_forked_repo:aaa-test-repo2-fork,2012-11-20 12:58:25.729374
1859 1922,3,demo,385,aaa-test-repo2-fork,"",user_created_fork:aaa-test-repo2-fork,2012-11-20 12:58:25.737204
1860 1923,3,demo,385,aaa-test-repo2-fork,"",push_local:af794c0c7cf39be92c6b59bb8b7871d313b1d248,2012-11-20 12:58:59.668087
1861 1924,3,demo,384,aaa-test-repo2,"",user_commented_pull_request:74,2012-11-20 13:25:32.773937
1862 1925,3,demo,384,aaa-test-repo2,"",user_commented_pull_request:74,2012-11-20 13:33:39.823854
1863 1926,3,demo,384,aaa-test-repo2,"",user_closed_pull_request:74,2012-11-20 13:33:39.828583
1864 1927,3,demo,385,aaa-test-repo2-fork,"",push_local:67120aaf6ddd81cd2aabde6adc22e7ca90d15d12,2012-11-20 18:41:48.280705
1865 1928,3,demo,384,aaa-test-repo2,81.178.131.20,"push:af794c0c7cf39be92c6b59bb8b7871d313b1d248,67120aaf6ddd81cd2aabde6adc22e7ca90d15d12",2012-11-20 20:01:34.101349
1866 1929,3,demo,385,aaa-test-repo2-fork,"",push_local:5ece07f12c61645049e7d2d3d33797942b16cba5,2012-11-20 20:10:49.816215
1867 1930,3,demo,385,aaa-test-repo2-fork,"",push_local:fd8a6936e27e3c31684155790f78effb33e6cc5c,2012-11-20 20:24:06.305599
1868 1931,3,demo,384,aaa-test-repo2,81.178.131.20,push:5ece07f12c61645049e7d2d3d33797942b16cba5,2012-11-20 20:49:00.180794
1869 1932,3,demo,384,aaa-test-repo2,81.178.131.20,push:fd8a6936e27e3c31684155790f78effb33e6cc5c,2012-11-20 21:28:16.281326
1870 1933,3,demo,384,aaa-test-repo2,"",user_commented_pull_request:75,2012-11-21 01:38:22.165876
1871 1934,3,demo,384,aaa-test-repo2,"",user_closed_pull_request:75,2012-11-21 01:38:22.175975
1872 1935,3,demo,385,aaa-test-repo2-fork,"",push_local:586be5737b6b185d37ab249e028470417698b44d,2012-11-21 01:42:21.540009
1873 1936,3,demo,385,aaa-test-repo2-fork,"",push_local:b836457cf5b358555c26193e67770d56e2345f4c,2012-11-21 01:50:03.178941
1874 1937,3,demo,384,aaa-test-repo2,81.178.131.20,"push:586be5737b6b185d37ab249e028470417698b44d,b836457cf5b358555c26193e67770d56e2345f4c",2012-11-21 02:01:01.40853
1875 1938,3,demo,34,a-very-long-usper-loooong-name-that-is-to-long,"",push_local:ff712eae5a99bede2bf710d86f86b0b534fbf089,2012-11-21 02:09:50.150788
1876 1939,3,demo,68,aaa-project,"",user_commented_revision:b4bf1f77b1288a24eb395537319b4f3155cffa71,2012-11-21 08:36:43.456525
1877 1940,3,demo,384,aaa-test-repo2,"",user_commented_revision:b836457cf5b358555c26193e67770d56e2345f4c,2012-11-21 12:03:06.317362
1878 1941,3,demo,385,aaa-test-repo2-fork,"",push_local:d38a759ba1f79489db44854c9ddf06986f7e2b72,2012-11-21 12:17:04.303085
1879 1942,3,demo,385,aaa-test-repo2-fork,"",user_commented_revision:d38a759ba1f79489db44854c9ddf06986f7e2b72,2012-11-21 12:17:47.536221
1880 1943,3,demo,34,a-very-long-usper-loooong-name-that-is-to-long,"",user_commented_revision:f437e821a406d35b1e231c5a81e82853f8ed6436,2012-11-21 14:27:15.134067
1881 1944,3,demo,386,I-am-a-very-long-repository-name-fork,"",started_following_repo,2012-11-21 15:31:17.25368
1882 1945,3,demo,348,group/I-am-a-very-long-repository-name,"",user_forked_repo:I-am-a-very-long-repository-name-fork,2012-11-21 15:31:17.271794
1883 1946,3,demo,386,I-am-a-very-long-repository-name-fork,"",user_created_fork:I-am-a-very-long-repository-name-fork,2012-11-21 15:31:17.283533
1884 1947,3,demo,385,aaa-test-repo2-fork,"",user_commented_revision:d38a759ba1f79489db44854c9ddf06986f7e2b72,2012-11-21 16:35:17.484282
1885 1948,3,demo,385,aaa-test-repo2-fork,"",push_local:96abb74e8e96a81a7dc5d472c70158da5318a623,2012-11-21 16:35:50.796373
1886 1949,3,demo,385,aaa-test-repo2-fork,"",user_commented_revision:96abb74e8e96a81a7dc5d472c70158da5318a623,2012-11-21 16:36:25.797019
1887 1950,2,admin,68,aaa-project,"",push_local:7db38281c68497cee8dc4510d77e03fbb4d6c395,2012-11-21 18:34:44.97296
1888 1951,2,admin,68,aaa-project,"",push_local:de5af01cc0f75ab84966b11806c343000eeeb5d8,2012-11-21 18:36:10.869973
1889 1952,3,demo,387,new-group-test-repos1,"",started_following_repo,2012-11-21 21:05:48.945007
1890 1953,3,demo,387,new-group-test-repos1,"",user_created_repo,2012-11-21 21:05:48.953815
1891 1954,3,demo,388,Logarithmic,"",started_following_repo,2012-11-22 11:30:39.744224
1892 1955,3,demo,388,Logarithmic,"",user_created_repo,2012-11-22 11:30:39.761413
1893 1956,3,demo,388,Logarithmic,"",push_local:72dd1a9ceecfcf9832e41dd66d355d5c63546b67,2012-11-22 11:35:30.523613
1894 1957,3,demo,388,Logarithmic,"",push_local:fdb124c2a063a7ce15a1b3e42cdfa30a5bf19fcb,2012-11-22 11:52:07.237429
1895 1958,364,hs_rcdemo,389,hsio_test,"",started_following_repo,2012-11-22 14:32:05.148189
1896 1959,364,hs_rcdemo,389,hsio_test,"",user_created_repo,2012-11-22 14:32:05.163464
1897 1960,364,hs_rcdemo,389,hsio_test,"",push_local:8777c89c909bfba8eaae07cf596cce85190d7789,2012-11-22 14:33:30.066876
1898 1961,364,hs_rcdemo,389,hsio_test,"",user_updated_repo,2012-11-22 14:45:19.518307
1899 1962,3,demo,390,ycxs,"",started_following_repo,2012-11-23 08:00:34.880042
1900 1963,3,demo,390,ycxs,"",user_created_repo,2012-11-23 08:00:34.889356
1901 1964,3,demo,110,django,"",user_commented_revision:129f1ac8484d63c2e61a44fb2a18dd17246c1c4d,2012-11-23 22:54:06.842764
1902 1965,3,demo,68,aaa-project,"",user_commented_revision:de5af01cc0f75ab84966b11806c343000eeeb5d8,2012-11-25 18:05:15.626452
1903 1966,373,roger,391,roger,"",started_following_repo,2012-11-27 10:19:17.098535
1904 1967,373,roger,391,roger,"",user_created_repo,2012-11-27 10:19:17.110165
1905 1968,373,roger,391,roger,195.67.17.194,push:3deefa3d90eb91fbfe7c7d97579842d26ffab526,2012-11-27 10:20:14.448706
1906 1969,373,roger,394,roger-fork,"",started_following_repo,2012-11-27 10:44:06.565014
1907 1970,373,roger,391,roger,"",user_forked_repo:roger-fork,2012-11-27 10:44:06.582941
1908 1971,373,roger,394,roger-fork,"",user_created_fork:roger-fork,2012-11-27 10:44:06.591697
1909 1972,373,roger,394,roger-fork,195.67.17.194,push:ef5703075e9bd3b498d0398be689c6ecc2aa68f2,2012-11-27 10:46:44.898629
1910 1973,373,roger,391,roger,"",user_commented_pull_request:77,2012-11-27 10:49:00.02305
1911 1974,373,roger,394,roger-fork,195.67.17.194,push:1f3690bd18da15796e2379ea2f82d510dbbfd634,2012-11-27 10:52:51.819376
1912 1975,373,roger,391,roger,"",user_commented_pull_request:78,2012-11-27 10:55:01.836362
1913 1976,373,roger,391,roger,"",user_closed_pull_request:78,2012-11-27 10:55:01.843519
1914 1977,373,roger,391,roger,"",user_commented_pull_request:77,2012-11-27 10:55:43.206231
1915 1978,373,roger,391,roger,"",user_updated_repo,2012-11-27 10:56:53.018675
1916 1979,373,roger,391,roger,"",user_updated_repo,2012-11-27 11:02:27.558462
1917 1980,373,roger,394,roger-fork,195.67.17.194,push:3a6d267941eeb0a8cd7be18d619d6fe370216f00,2012-11-27 11:04:37.480288
1918 1981,374,roger2,391,roger,"",user_commented_pull_request:79,2012-11-27 11:05:56.858694
1919 1982,374,roger2,391,roger,"",user_commented_pull_request:79,2012-11-27 11:06:02.182164
1920 1983,374,roger2,391,roger,"",user_commented_pull_request:79,2012-11-27 11:06:38.109374
1921 1984,374,roger2,391,roger,"",user_commented_pull_request:79,2012-11-27 11:07:34.474704
1922 1985,374,roger2,391,roger,"",user_closed_pull_request:79,2012-11-27 11:07:34.485308
1923 1986,373,roger,394,roger-fork,195.67.17.194,push:12cd31bebc666a85f8a0f0742093d5cd9ea585c4,2012-11-27 11:09:08.04061
1924 1987,373,roger,395,rogerfork2,"",started_following_repo,2012-11-27 11:11:04.332674
1925 1988,373,roger,391,roger,"",user_forked_repo:rogerfork2,2012-11-27 11:11:04.348686
1926 1989,373,roger,395,rogerfork2,"",user_created_fork:rogerfork2,2012-11-27 11:11:04.359388
1927 1990,373,roger,395,rogerfork2,195.67.17.194,"push:ef5703075e9bd3b498d0398be689c6ecc2aa68f2,1f3690bd18da15796e2379ea2f82d510dbbfd634,3a6d267941eeb0a8cd7be18d619d6fe370216f00,12cd31bebc666a85f8a0f0742093d5cd9ea585c4",2012-11-27 11:11:18.920484
1928 1991,373,roger,391,roger,"",user_commented_pull_request:80,2012-11-27 11:12:23.228709
1929 1992,373,roger,391,roger,"",user_commented_pull_request:80,2012-11-27 11:12:55.017541
1930 1993,373,roger,391,roger,"",user_closed_pull_request:80,2012-11-27 11:12:55.027814
1931 1994,3,demo,385,aaa-test-repo2-fork,"",push_local:872eeeb3a8a2783129bfd7d988323f5addac7ab1,2012-11-27 11:48:48.630984
1932 1995,3,demo,384,aaa-test-repo2,"",user_commented_pull_request:76,2012-11-27 11:50:01.915064
1933 1996,3,demo,384,aaa-test-repo2,"",user_commented_pull_request:76,2012-11-27 11:50:12.991796
1934 1997,3,demo,384,aaa-test-repo2,"",user_closed_pull_request:76,2012-11-27 11:50:12.99591
1935 1998,3,demo,396,тСстовый-сСрвСр,"",started_following_repo,2012-11-28 07:53:39.536654
1936 1999,3,demo,396,тСстовый-сСрвСр,"",user_created_repo,2012-11-28 07:53:39.550591
1937 2000,3,demo,397,simple-dev-fork,"",started_following_repo,2012-11-28 09:13:25.051649
1938 2001,3,demo,210,simple-dev,"",user_forked_repo:simple-dev-fork,2012-11-28 09:13:25.106104
1939 2002,3,demo,397,simple-dev-fork,"",user_created_fork:simple-dev-fork,2012-11-28 09:13:25.114908
1940 2003,3,demo,385,aaa-test-repo2-fork,"",user_commented_revision:96abb74e8e96a81a7dc5d472c70158da5318a623,2012-11-28 12:24:53.581825
1941 2004,3,demo,385,aaa-test-repo2-fork,"",user_commented_revision:872eeeb3a8a2783129bfd7d988323f5addac7ab1,2012-11-28 12:25:16.961119
1942 2005,3,demo,398,aaa-project-fork-fork,"",started_following_repo,2012-11-29 14:08:09.275983
1943 2006,3,demo,68,aaa-project,"",user_forked_repo:aaa-project-fork-fork,2012-11-29 14:08:09.413733
1944 2007,3,demo,398,aaa-project-fork-fork,"",user_created_fork:aaa-project-fork-fork,2012-11-29 14:08:09.427854
1945 2008,3,demo,68,aaa-project,"",user_updated_repo,2012-11-29 14:09:10.934065
1946 2009,3,demo,68,aaa-project,"",user_updated_repo,2012-11-29 14:09:24.706033
1947 2010,3,demo,399,tra,"",started_following_repo,2012-11-29 14:11:48.839858
1948 2011,3,demo,399,tra,"",user_created_repo,2012-11-29 14:11:48.85278
1949 2012,3,demo,42,foo,"",user_commented_revision:1b9a14ca778d48ebef5643f7aa2ce142f3a27617,2012-11-29 20:05:08.767523
1950 2013,3,demo,42,foo,"",push_local:bb4dab01c0bd4241b903a4dc84a79c70a01b0f6b,2012-11-29 20:06:18.477822
1951 2014,1,default,159,group/Test-for-code-review,"",push_local:eaca071ebe45eaf5fc6631b15d7cf079a0d5aaf1,2012-11-29 23:52:50.718898
1952 2015,375,paul,400,hophop,"",started_following_repo,2012-11-30 08:50:31.403305
1953 2016,375,paul,400,hophop,"",user_created_repo,2012-11-30 08:50:31.416463
1954 2017,375,paul,400,hophop,"",push_local:558613aaa69def5e130b8f9583de37f911a80dd8,2012-11-30 08:51:37.956737
1955 2018,375,paul,401,flepflep,"",started_following_repo,2012-11-30 08:52:56.146141
1956 2019,375,paul,400,hophop,"",user_forked_repo:flepflep,2012-11-30 08:52:56.162784
1957 2020,375,paul,401,flepflep,"",user_created_fork:flepflep,2012-11-30 08:52:56.171068
1958 2021,375,paul,400,hophop,213.154.235.68,push:0c64f45ec8f43a5267d593a2af65c3b9965c312c,2012-11-30 08:54:23.238053
1959 2022,376,mrntest,402,mrntest,"",started_following_repo,2012-11-30 10:10:14.463671
1960 2023,376,mrntest,402,mrntest,"",user_created_repo,2012-11-30 10:10:14.475507
1961 2024,1,default,159,group/Test-for-code-review,"",push_local:da1270d35961130d6fe12ba4777f412dabb533f7,2012-11-30 18:39:23.68212
1962 2025,3,demo,177,blah,"",user_updated_repo,2012-11-30 21:43:04.925873
1963 2026,1,default,159,group/Test-for-code-review,"",push_local:3bfcf2015dcc85f3334a4439099b1f4fe2ab87cc,2012-12-01 04:40:25.326381
1964 2027,3,demo,385,aaa-test-repo2-fork,"",push_local:8caf16b59f0ac54d002daeaf54208319a055829a,2012-12-01 12:40:27.987379
1965 2028,3,demo,385,aaa-test-repo2-fork,"",user_commented_revision:8caf16b59f0ac54d002daeaf54208319a055829a,2012-12-01 12:40:35.315142
1966 2029,3,demo,403,aaa-test-repo2-fork1,"",started_following_repo,2012-12-01 12:43:30.698526
1967 2030,3,demo,384,aaa-test-repo2,"",user_forked_repo:aaa-test-repo2-fork1,2012-12-01 12:43:30.7817
1968 2031,3,demo,403,aaa-test-repo2-fork1,"",user_created_fork:aaa-test-repo2-fork1,2012-12-01 12:43:30.789849
1969 2032,3,demo,403,aaa-test-repo2-fork1,"",push_local:7d46cab71f090b82e40f82aa164a237bffae8ca8,2012-12-01 12:43:54.847211
1970 2033,3,demo,384,aaa-test-repo2,"",user_commented_pull_request:81,2012-12-01 12:45:15.004235
1971 2034,3,demo,384,aaa-test-repo2,"",user_closed_pull_request:81,2012-12-01 12:45:15.01175
1972 2035,1,default,159,group/Test-for-code-review,"",push_local:88f2b300127f7249d6b2ac03d4e368cd7a043073,2012-12-02 06:49:39.201427
1973 2036,380,han,42,foo,"",user_commented_revision:ca953e8c5c1ada44e9a8f945a0a6999d2f44310d,2012-12-03 05:54:40.845102
1974 2037,380,han,42,foo,"",user_commented_revision:ca953e8c5c1ada44e9a8f945a0a6999d2f44310d,2012-12-03 05:54:52.733614
1975 2038,380,han,42,foo,"",user_commented_revision:ca953e8c5c1ada44e9a8f945a0a6999d2f44310d,2012-12-03 05:55:06.032348
1976 2039,380,han,184,fork-aaa-project,"",user_commented_revision:e3fef0be8dc20eb1fa68fc45292d9d66de1cc67f,2012-12-03 05:55:57.293424
1977 2040,380,han,184,fork-aaa-project,"",user_commented_revision:e3fef0be8dc20eb1fa68fc45292d9d66de1cc67f,2012-12-03 05:56:05.503132
1978 2041,380,han,184,fork-aaa-project,"",user_commented_revision:e3fef0be8dc20eb1fa68fc45292d9d66de1cc67f,2012-12-03 05:56:11.78452
1979 2042,381,tmilos,265,mercurial-trunk,"",user_commented_revision:b3f0f9a39c4e1d0250048cd803ab03542d6f140a,2012-12-03 08:18:24.126434
1980 2043,381,tmilos,265,mercurial-trunk,"",user_commented_revision:b3f0f9a39c4e1d0250048cd803ab03542d6f140a,2012-12-03 08:18:53.783535
1981 2044,3,demo,68,aaa-project,"",user_commented_revision:0c33fa58efc5a5541d8d3f1a3d3b77367e3d94f5,2012-12-03 13:51:26.584571
1982 2045,3,demo,384,aaa-test-repo2,"",user_updated_repo,2012-12-03 13:59:51.134475
1983 2046,3,demo,68,aaa-project,"",user_updated_repo,2012-12-03 14:12:42.587904
1984 2047,3,demo,404,Test-Repo-5,"",started_following_repo,2012-12-03 19:58:28.17924
1985 2048,3,demo,404,Test-Repo-5,"",admin_created_repo,2012-12-03 19:58:28.215537
1986 2049,3,demo,382,aaa-repo-fork,"",push_local:d49133c59d2b74bf5754fab639520fe0f15f660b,2012-12-03 23:45:38.954154
1987 2050,5,natosha.bard,405,test-largefiles-push,"",started_following_repo,2012-12-04 14:15:02.062567
1988 2051,5,natosha.bard,405,test-largefiles-push,"",admin_created_repo,2012-12-04 14:15:02.07345
1989 2052,5,natosha.bard,405,test-largefiles-push,62.116.219.97,push:3055a4c8ccb9b695a7973aa25aa118b0dde122e4,2012-12-04 14:15:19.101956
1990 2053,5,natosha.bard,405,test-largefiles-push,62.116.219.97,push:88adc5944c74488164ae575511429ed582a72e17,2012-12-04 14:40:10.373812
1991 2054,384,test1234,406,test123456,"",started_following_repo,2012-12-04 16:07:07.967514
1992 2055,384,test1234,406,test123456,"",admin_created_repo,2012-12-04 16:07:07.987393
1993 2058,5,natosha.bard,408,test-repo-natosha,"",started_following_repo,2012-12-04 20:41:39.763055
1994 2059,5,natosha.bard,408,test-repo-natosha,"",admin_created_repo,2012-12-04 20:41:39.775062
1995 2056,5,natosha.bard,,hg,"",started_following_repo,2012-12-04 20:40:00.327829
1996 2057,5,natosha.bard,,hg,"",admin_created_repo,2012-12-04 20:40:00.342796
1997 2060,5,natosha.bard,,hg,"",user_deleted_repo,2012-12-04 20:42:03.236535
1998 2062,5,natosha.bard,409,test-repo-natosha-fork,"",started_following_repo,2012-12-04 20:43:25.363199
1999 2063,5,natosha.bard,408,test-repo-natosha,"",user_forked_repo:test-repo-natosha-fork,2012-12-04 20:43:25.413303
2000 2064,5,natosha.bard,409,test-repo-natosha-fork,"",user_created_fork:test-repo-natosha-fork,2012-12-04 20:43:25.421503
2001 2065,5,natosha.bard,409,test-repo-natosha-fork,62.116.219.97,"push:132a288f32d5b70a9170e504028c693cfffc5c39,fac6d36d04cb1838cd10bdcecd487567787fb853,e83c482c6c5fd60f14d1a5f5cf9b4f7b2a2eb3cb,ce2c709a8e908747376a3fda6059c1f81de321e7,45bd0cd7ca04f8cda0a61cddded8838dd312675a,35ba170c0f82dba18f0207ef4bd93216e6de8bbf,407209261f6373b4b3f35e343d1498b63263d38e,6f79c32c0bdfb304b984b5e6ba318cc63032cfa4,54cedee86e5126188b0dcfbd7015bcdca7f6c2e2,b0affcb67cba58db03ca3e443105fbaabd1bc88a,4c29668ca316422891e28c55bd794eee52823554,6180dcb29ec531c5d7457005ef142ea304ef49d8,2c63896783e31908f18088a7e9c583de6ec530bf,b3ec0b5fd7771b401392a83f47e0c2360e7f6d90,e689b0d9154605b8b04989c4fdd36e76d6cf26b8,b74361cf7c0ad6930a865e7eada13e2d2d6ed380,f94ead93406764ffd0c3febfc2ea70d36a2a28bb,848345a8d6adaa58704baecbb7567b275df3cc9d,0c10cf8191469e7c3c8844922e17e71a176cb7cb",2012-12-04 20:44:13.658236
2002 2066,1,default,159,group/Test-for-code-review,"",push_local:b77f1d54f1d18c22e497f1d9d502e0d540506d21,2012-12-05 00:22:33.617864
2003 2067,3,demo,410,aaa-project-fork-fork-fork-fork-fork-blah,"",started_following_repo,2012-12-05 10:07:05.333082
2004 2068,3,demo,398,aaa-project-fork-fork,"",user_forked_repo:aaa-project-fork-fork-fork-fork-fork-blah,2012-12-05 10:07:05.47808
2005 2069,3,demo,410,aaa-project-fork-fork-fork-fork-fork-blah,"",user_created_fork:aaa-project-fork-fork-fork-fork-fork-blah,2012-12-05 10:07:05.487482
2006 2070,387,ssssss,411,sss-test,"",started_following_repo,2012-12-05 13:33:27.008097
2007 2071,387,ssssss,411,sss-test,"",admin_created_repo,2012-12-05 13:33:27.018183
2008 2072,387,ssssss,411,sss-test,"",user_updated_repo,2012-12-05 13:37:35.771478
2009 2073,387,ssssss,411,sss-test,"",user_updated_repo,2012-12-05 13:38:00.979078
2010 2074,387,ssssss,411,sss-test,"",user_updated_repo,2012-12-05 13:38:05.497667
2011 2075,387,ssssss,411,sss-test,"",user_updated_repo,2012-12-05 13:38:12.513828
2012 2076,387,ssssss,173,code-review-dev,"",started_following_repo,2012-12-05 13:46:51.940453
2013 2077,387,ssssss,173,code-review-dev,"",stopped_following_repo,2012-12-05 13:46:54.738489
2014 2078,387,ssssss,411,sss-test,109.195.177.171,push:7d42587da267871709bc82e462018b8b7d66a4a7,2012-12-05 13:59:09.546916
2015 2079,387,ssssss,411,sss-test,109.195.177.171,push:bb869421c7c8f88590536d559cebd3ee5e9c3aa7,2012-12-05 14:00:27.04582
2016 2080,387,ssssss,411,sss-test,"",user_updated_repo,2012-12-05 14:03:48.47955
2017 2081,389,wwwwww,412,sss-test-fork,"",started_following_repo,2012-12-05 14:05:13.355226
2018 2082,389,wwwwww,411,sss-test,"",user_forked_repo:sss-test-fork,2012-12-05 14:05:13.663527
2019 2083,389,wwwwww,412,sss-test-fork,"",user_created_fork:sss-test-fork,2012-12-05 14:05:13.678367
2020 2084,389,wwwwww,412,sss-test-fork,"",user_updated_repo,2012-12-05 14:05:56.566769
2021 2085,389,wwwwww,412,sss-test-fork,109.195.177.171,push:20bd46e65a056aef107cc060d16c97b1ef2cc211,2012-12-05 14:07:21.399133
2022 2086,389,wwwwww,412,sss-test-fork,"",user_commented_revision:20bd46e65a056aef107cc060d16c97b1ef2cc211,2012-12-05 14:16:56.716099
2023 2087,387,ssssss,411,sss-test,"",user_updated_repo,2012-12-05 14:20:41.385001
2024 2088,389,wwwwww,411,sss-test,109.195.177.171,push:20bd46e65a056aef107cc060d16c97b1ef2cc211,2012-12-05 14:20:54.878385
2025 2089,387,ssssss,411,sss-test,"",user_updated_repo,2012-12-05 14:21:15.330812
2026 2090,389,wwwwww,412,sss-test-fork,109.195.177.171,push:1203172be2e12aa31ec40ba4d07b75a3e17bd63f,2012-12-05 14:23:18.297453
2027 2091,389,wwwwww,412,sss-test-fork,"",user_commented_revision:1203172be2e12aa31ec40ba4d07b75a3e17bd63f,2012-12-05 14:23:34.233486
2028 2092,5,natosha.bard,413,natosha-repo1,"",started_following_repo,2012-12-05 16:46:55.328513
2029 2093,5,natosha.bard,413,natosha-repo1,"",admin_created_repo,2012-12-05 16:46:55.342146
2030 2094,5,natosha.bard,413,natosha-repo1,62.116.219.97,"push:6fbe2a2357168359aacbc524f4acd805dff72327,5787c391ba8f9d67b4e96f47d71adab79b693a30",2012-12-05 16:47:09.181828
2031 2095,5,natosha.bard,414,natosha-repo1-fork,"",started_following_repo,2012-12-05 16:47:24.080447
2032 2096,5,natosha.bard,413,natosha-repo1,"",user_forked_repo:natosha-repo1-fork,2012-12-05 16:47:24.101525
2033 2097,5,natosha.bard,414,natosha-repo1-fork,"",user_created_fork:natosha-repo1-fork,2012-12-05 16:47:24.113866
2034 2098,5,natosha.bard,414,natosha-repo1-fork,62.116.219.97,"push:a25c825fd81d069596d614efcf92505aed46227a,ac513595518923aca8b39f0a1c33c4c6e0f9d83a,d395e22e8e16373a1fffbe66b322581d69a7db17",2012-12-05 16:47:44.701535
2035 2099,2,admin,38,code-review-test,"",user_commented_pull_request:73,2012-12-05 17:23:18.059481
@@ -1,143 +1,142 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.admin
3 rhodecode.controllers.admin.admin
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Controller for Admin panel of Rhodecode
6 Controller for Admin panel of Rhodecode
7
7
8 :created_on: Apr 7, 2010
8 :created_on: Apr 7, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27
27
28 from pylons import request, tmpl_context as c, url
28 from pylons import request, tmpl_context as c, url
29 from sqlalchemy.orm import joinedload
29 from sqlalchemy.orm import joinedload
30 from webhelpers.paginate import Page
30 from webhelpers.paginate import Page
31 from whoosh.qparser.default import QueryParser
31 from whoosh.qparser.default import QueryParser
32 from whoosh import query
32 from whoosh import query
33 from sqlalchemy.sql.expression import or_
33 from sqlalchemy.sql.expression import or_
34
34
35 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
35 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
36 from rhodecode.lib.base import BaseController, render
36 from rhodecode.lib.base import BaseController, render
37 from rhodecode.model.db import UserLog, User
37 from rhodecode.model.db import UserLog, User
38 from rhodecode.lib.utils2 import safe_int, remove_prefix
38 from rhodecode.lib.utils2 import safe_int, remove_prefix, remove_suffix
39 from rhodecode.lib.indexers import JOURNAL_SCHEMA
39 from rhodecode.lib.indexers import JOURNAL_SCHEMA
40
40
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44
45 def _filter(user_log, search_term):
45 def _filter(user_log, search_term):
46 """
46 """
47 Filters sqlalchemy user_log based on search_term with whoosh Query language
47 Filters sqlalchemy user_log based on search_term with whoosh Query language
48 http://packages.python.org/Whoosh/querylang.html
48 http://packages.python.org/Whoosh/querylang.html
49
49
50 :param user_log:
50 :param user_log:
51 :param search_term:
51 :param search_term:
52 """
52 """
53 log.debug('Initial search term: %r' % search_term)
53 qry = None
54 qry = None
54 if search_term:
55 if search_term:
55 qp = QueryParser('repository', schema=JOURNAL_SCHEMA)
56 qp = QueryParser('repository', schema=JOURNAL_SCHEMA)
56 qry = qp.parse(unicode(search_term))
57 qry = qp.parse(unicode(search_term))
57 log.debug('Filtering using query %r' % qry)
58 log.debug('Filtering using parsed query %r' % qry)
59
60 def wildcard_handler(col, wc_term):
61 if wc_term.startswith('*') and not wc_term.endswith('*'):
62 #postfix == endswith
63 wc_term = remove_prefix(wc_term, prefix='*')
64 return getattr(col, 'endswith')(wc_term)
65 elif wc_term.startswith('*') and wc_term.endswith('*'):
66 #wildcard == ilike
67 wc_term = remove_prefix(wc_term, prefix='*')
68 wc_term = remove_suffix(wc_term, suffix='*')
69 return getattr(col, 'contains')(wc_term)
58
70
59 def get_filterion(field, val, term):
71 def get_filterion(field, val, term):
72
60 if field == 'repository':
73 if field == 'repository':
61 field = getattr(UserLog, 'repository_name')
74 field = getattr(UserLog, 'repository_name')
62 elif field == 'ip':
75 elif field == 'ip':
63 field = getattr(UserLog, 'user_ip')
76 field = getattr(UserLog, 'user_ip')
64 elif field == 'date':
77 elif field == 'date':
65 field = getattr(UserLog, 'action_date')
78 field = getattr(UserLog, 'action_date')
66 elif field == 'username':
79 elif field == 'username':
67 ##special case for username
80 field = getattr(UserLog, 'username')
68 if isinstance(term, query.Wildcard):
69 #only support wildcards with * at beggining
70 val = remove_prefix(val, prefix='*')
71 return getattr(UserLog, 'user_id').in_(
72 [x.user_id for x in
73 User.query().filter(User.username.endswith(val))])
74 elif isinstance(term, query.Prefix):
75 return getattr(UserLog, 'user_id').in_(
76 [x.user_id for x in
77 User.query().filter(User.username.startswith(val))])
78 # term == exact match, case insensitive
79 field = getattr(UserLog, 'user')
80 val = User.get_by_username(val, case_insensitive=True)
81
82 else:
81 else:
83 field = getattr(UserLog, field)
82 field = getattr(UserLog, field)
83 log.debug('filter field: %s val=>%s' % (field, val))
84
84
85 #sql filtering
85 #sql filtering
86 if isinstance(term, query.Wildcard):
86 if isinstance(term, query.Wildcard):
87 return field.endsswith(val)
87 return wildcard_handler(field, val)
88 elif isinstance(term, query.Prefix):
88 elif isinstance(term, query.Prefix):
89 return field.startswith(val)
89 return field.startswith(val)
90 return field == val
90 return field == val
91
91
92 if isinstance(qry, (query.And, query.Term, query.Prefix, query.Wildcard)):
92 if isinstance(qry, (query.And, query.Term, query.Prefix, query.Wildcard)):
93 if not isinstance(qry, query.And):
93 if not isinstance(qry, query.And):
94 qry = [qry]
94 qry = [qry]
95 for term in qry:
95 for term in qry:
96 field = term.fieldname
96 field = term.fieldname
97 val = term.text
97 val = term.text
98 user_log = user_log.filter(get_filterion(field, val, term))
98 user_log = user_log.filter(get_filterion(field, val, term))
99 elif isinstance(qry, query.Or):
99 elif isinstance(qry, query.Or):
100 filters = []
100 filters = []
101 for term in qry:
101 for term in qry:
102 field = term.fieldname
102 field = term.fieldname
103 val = term.text
103 val = term.text
104 if isinstance(term, query.Term):
104 filters.append(get_filterion(field, val, term))
105 filters.append(get_filterion(field, val, term))
106 user_log = user_log.filter(or_(*filters))
105 user_log = user_log.filter(or_(*filters))
107
106
108 return user_log
107 return user_log
109
108
110
109
111 class AdminController(BaseController):
110 class AdminController(BaseController):
112
111
113 @LoginRequired()
112 @LoginRequired()
114 def __before__(self):
113 def __before__(self):
115 super(AdminController, self).__before__()
114 super(AdminController, self).__before__()
116
115
117 @HasPermissionAllDecorator('hg.admin')
116 @HasPermissionAllDecorator('hg.admin')
118 def index(self):
117 def index(self):
119 users_log = UserLog.query()\
118 users_log = UserLog.query()\
120 .options(joinedload(UserLog.user))\
119 .options(joinedload(UserLog.user))\
121 .options(joinedload(UserLog.repository))
120 .options(joinedload(UserLog.repository))
122
121
123 #FILTERING
122 #FILTERING
124 c.search_term = request.GET.get('filter')
123 c.search_term = request.GET.get('filter')
125 try:
124 try:
126 users_log = _filter(users_log, c.search_term)
125 users_log = _filter(users_log, c.search_term)
127 except:
126 except:
128 # we want this to crash for now
127 # we want this to crash for now
129 raise
128 raise
130
129
131 users_log = users_log.order_by(UserLog.action_date.desc())
130 users_log = users_log.order_by(UserLog.action_date.desc())
132
131
133 p = safe_int(request.params.get('page', 1), 1)
132 p = safe_int(request.params.get('page', 1), 1)
134
133
135 def url_generator(**kw):
134 def url_generator(**kw):
136 return url.current(filter=c.search_term, **kw)
135 return url.current(filter=c.search_term, **kw)
137
136
138 c.users_log = Page(users_log, page=p, items_per_page=10, url=url_generator)
137 c.users_log = Page(users_log, page=p, items_per_page=10, url=url_generator)
139 c.log_data = render('admin/admin_log.html')
138 c.log_data = render('admin/admin_log.html')
140
139
141 if request.environ.get('HTTP_X_PARTIAL_XHR'):
140 if request.environ.get('HTTP_X_PARTIAL_XHR'):
142 return c.log_data
141 return c.log_data
143 return render('admin/admin.html')
142 return render('admin/admin.html')
@@ -1,29 +1,47 b''
1 import logging
1 import logging
2 import datetime
2 import datetime
3
3
4 from sqlalchemy import *
4 from sqlalchemy import *
5 from sqlalchemy.exc import DatabaseError
5 from sqlalchemy.exc import DatabaseError
6 from sqlalchemy.orm import relation, backref, class_mapper
6 from sqlalchemy.orm import relation, backref, class_mapper, joinedload
7 from sqlalchemy.orm.session import Session
7 from sqlalchemy.orm.session import Session
8 from sqlalchemy.ext.declarative import declarative_base
8 from sqlalchemy.ext.declarative import declarative_base
9
9
10 from rhodecode.lib.dbmigrate.migrate import *
10 from rhodecode.lib.dbmigrate.migrate import *
11 from rhodecode.lib.dbmigrate.migrate.changeset import *
11 from rhodecode.lib.dbmigrate.migrate.changeset import *
12
12
13 from rhodecode.model.meta import Base
13 from rhodecode.model.meta import Base
14 from rhodecode.model import meta
14 from rhodecode.model import meta
15
15
16 log = logging.getLogger(__name__)
16 log = logging.getLogger(__name__)
17
17
18
18
19 def upgrade(migrate_engine):
19 def upgrade(migrate_engine):
20 """
20 """
21 Upgrade operations go here.
21 Upgrade operations go here.
22 Don't create your own engine; bind migrate_engine to your metadata
22 Don't create your own engine; bind migrate_engine to your metadata
23 """
23 """
24 pass
24 #==========================================================================
25 # USER LOGS
26 #==========================================================================
27 from rhodecode.lib.dbmigrate.schema.db_1_5_0 import UserLog
28 tbl = UserLog.__table__
29 username = Column("username", String(255, convert_unicode=False,
30 assert_unicode=None), nullable=True,
31 unique=None, default=None)
32 # create username column
33 username.create(table=tbl)
34
35 ## after adding that column fix all usernames
36 users_log = UserLog.query()\
37 .options(joinedload(UserLog.user))\
38 .options(joinedload(UserLog.repository)).all()
39 for entry in users_log:
40 entry.username = entry.user.username
41 Session().add(entry)
42 Session().commit()
25
43
26
44
27 def downgrade(migrate_engine):
45 def downgrade(migrate_engine):
28 meta = MetaData()
46 meta = MetaData()
29 meta.bind = migrate_engine
47 meta.bind = migrate_engine
@@ -1,1133 +1,1137 b''
1 """Helper functions
1 """Helper functions
2
2
3 Consists of functions to typically be used within templates, but also
3 Consists of functions to typically be used within templates, but also
4 available to Controllers. This module is available to both as 'h'.
4 available to Controllers. This module is available to both as 'h'.
5 """
5 """
6 import random
6 import random
7 import hashlib
7 import hashlib
8 import StringIO
8 import StringIO
9 import urllib
9 import urllib
10 import math
10 import math
11 import logging
11 import logging
12 import re
12 import re
13 import urlparse
13 import urlparse
14
14
15 from datetime import datetime
15 from datetime import datetime
16 from pygments.formatters.html import HtmlFormatter
16 from pygments.formatters.html import HtmlFormatter
17 from pygments import highlight as code_highlight
17 from pygments import highlight as code_highlight
18 from pylons import url, request, config
18 from pylons import url, request, config
19 from pylons.i18n.translation import _, ungettext
19 from pylons.i18n.translation import _, ungettext
20 from hashlib import md5
20 from hashlib import md5
21
21
22 from webhelpers.html import literal, HTML, escape
22 from webhelpers.html import literal, HTML, escape
23 from webhelpers.html.tools import *
23 from webhelpers.html.tools import *
24 from webhelpers.html.builder import make_tag
24 from webhelpers.html.builder import make_tag
25 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
25 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
26 end_form, file, form, hidden, image, javascript_link, link_to, \
26 end_form, file, form, hidden, image, javascript_link, link_to, \
27 link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
27 link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
28 submit, text, password, textarea, title, ul, xml_declaration, radio
28 submit, text, password, textarea, title, ul, xml_declaration, radio
29 from webhelpers.html.tools import auto_link, button_to, highlight, \
29 from webhelpers.html.tools import auto_link, button_to, highlight, \
30 js_obfuscate, mail_to, strip_links, strip_tags, tag_re
30 js_obfuscate, mail_to, strip_links, strip_tags, tag_re
31 from webhelpers.number import format_byte_size, format_bit_size
31 from webhelpers.number import format_byte_size, format_bit_size
32 from webhelpers.pylonslib import Flash as _Flash
32 from webhelpers.pylonslib import Flash as _Flash
33 from webhelpers.pylonslib.secure_form import secure_form
33 from webhelpers.pylonslib.secure_form import secure_form
34 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
34 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
35 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
35 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
36 replace_whitespace, urlify, truncate, wrap_paragraphs
36 replace_whitespace, urlify, truncate, wrap_paragraphs
37 from webhelpers.date import time_ago_in_words
37 from webhelpers.date import time_ago_in_words
38 from webhelpers.paginate import Page
38 from webhelpers.paginate import Page
39 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
39 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
40 convert_boolean_attrs, NotGiven, _make_safe_id_component
40 convert_boolean_attrs, NotGiven, _make_safe_id_component
41
41
42 from rhodecode.lib.annotate import annotate_highlight
42 from rhodecode.lib.annotate import annotate_highlight
43 from rhodecode.lib.utils import repo_name_slug
43 from rhodecode.lib.utils import repo_name_slug
44 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
44 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
45 get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict
45 get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict
46 from rhodecode.lib.markup_renderer import MarkupRenderer
46 from rhodecode.lib.markup_renderer import MarkupRenderer
47 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
47 from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError
48 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
48 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset
49 from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
49 from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
50 from rhodecode.model.changeset_status import ChangesetStatusModel
50 from rhodecode.model.changeset_status import ChangesetStatusModel
51 from rhodecode.model.db import URL_SEP, Permission
51 from rhodecode.model.db import URL_SEP, Permission
52
52
53 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
54
54
55
55
56 html_escape_table = {
56 html_escape_table = {
57 "&": "&amp;",
57 "&": "&amp;",
58 '"': "&quot;",
58 '"': "&quot;",
59 "'": "&apos;",
59 "'": "&apos;",
60 ">": "&gt;",
60 ">": "&gt;",
61 "<": "&lt;",
61 "<": "&lt;",
62 }
62 }
63
63
64
64
65 def html_escape(text):
65 def html_escape(text):
66 """Produce entities within text."""
66 """Produce entities within text."""
67 return "".join(html_escape_table.get(c, c) for c in text)
67 return "".join(html_escape_table.get(c, c) for c in text)
68
68
69
69
70 def shorter(text, size=20):
70 def shorter(text, size=20):
71 postfix = '...'
71 postfix = '...'
72 if len(text) > size:
72 if len(text) > size:
73 return text[:size - len(postfix)] + postfix
73 return text[:size - len(postfix)] + postfix
74 return text
74 return text
75
75
76
76
77 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
77 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
78 """
78 """
79 Reset button
79 Reset button
80 """
80 """
81 _set_input_attrs(attrs, type, name, value)
81 _set_input_attrs(attrs, type, name, value)
82 _set_id_attr(attrs, id, name)
82 _set_id_attr(attrs, id, name)
83 convert_boolean_attrs(attrs, ["disabled"])
83 convert_boolean_attrs(attrs, ["disabled"])
84 return HTML.input(**attrs)
84 return HTML.input(**attrs)
85
85
86 reset = _reset
86 reset = _reset
87 safeid = _make_safe_id_component
87 safeid = _make_safe_id_component
88
88
89
89
90 def FID(raw_id, path):
90 def FID(raw_id, path):
91 """
91 """
92 Creates a uniqe ID for filenode based on it's hash of path and revision
92 Creates a uniqe ID for filenode based on it's hash of path and revision
93 it's safe to use in urls
93 it's safe to use in urls
94
94
95 :param raw_id:
95 :param raw_id:
96 :param path:
96 :param path:
97 """
97 """
98
98
99 return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12])
99 return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12])
100
100
101
101
102 def get_token():
102 def get_token():
103 """Return the current authentication token, creating one if one doesn't
103 """Return the current authentication token, creating one if one doesn't
104 already exist.
104 already exist.
105 """
105 """
106 token_key = "_authentication_token"
106 token_key = "_authentication_token"
107 from pylons import session
107 from pylons import session
108 if not token_key in session:
108 if not token_key in session:
109 try:
109 try:
110 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
110 token = hashlib.sha1(str(random.getrandbits(128))).hexdigest()
111 except AttributeError: # Python < 2.4
111 except AttributeError: # Python < 2.4
112 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
112 token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest()
113 session[token_key] = token
113 session[token_key] = token
114 if hasattr(session, 'save'):
114 if hasattr(session, 'save'):
115 session.save()
115 session.save()
116 return session[token_key]
116 return session[token_key]
117
117
118
118
119 class _GetError(object):
119 class _GetError(object):
120 """Get error from form_errors, and represent it as span wrapped error
120 """Get error from form_errors, and represent it as span wrapped error
121 message
121 message
122
122
123 :param field_name: field to fetch errors for
123 :param field_name: field to fetch errors for
124 :param form_errors: form errors dict
124 :param form_errors: form errors dict
125 """
125 """
126
126
127 def __call__(self, field_name, form_errors):
127 def __call__(self, field_name, form_errors):
128 tmpl = """<span class="error_msg">%s</span>"""
128 tmpl = """<span class="error_msg">%s</span>"""
129 if form_errors and field_name in form_errors:
129 if form_errors and field_name in form_errors:
130 return literal(tmpl % form_errors.get(field_name))
130 return literal(tmpl % form_errors.get(field_name))
131
131
132 get_error = _GetError()
132 get_error = _GetError()
133
133
134
134
135 class _ToolTip(object):
135 class _ToolTip(object):
136
136
137 def __call__(self, tooltip_title, trim_at=50):
137 def __call__(self, tooltip_title, trim_at=50):
138 """
138 """
139 Special function just to wrap our text into nice formatted
139 Special function just to wrap our text into nice formatted
140 autowrapped text
140 autowrapped text
141
141
142 :param tooltip_title:
142 :param tooltip_title:
143 """
143 """
144 tooltip_title = escape(tooltip_title)
144 tooltip_title = escape(tooltip_title)
145 tooltip_title = tooltip_title.replace('<', '&lt;').replace('>', '&gt;')
145 tooltip_title = tooltip_title.replace('<', '&lt;').replace('>', '&gt;')
146 return tooltip_title
146 return tooltip_title
147 tooltip = _ToolTip()
147 tooltip = _ToolTip()
148
148
149
149
150 class _FilesBreadCrumbs(object):
150 class _FilesBreadCrumbs(object):
151
151
152 def __call__(self, repo_name, rev, paths):
152 def __call__(self, repo_name, rev, paths):
153 if isinstance(paths, str):
153 if isinstance(paths, str):
154 paths = safe_unicode(paths)
154 paths = safe_unicode(paths)
155 url_l = [link_to(repo_name, url('files_home',
155 url_l = [link_to(repo_name, url('files_home',
156 repo_name=repo_name,
156 repo_name=repo_name,
157 revision=rev, f_path=''),
157 revision=rev, f_path=''),
158 class_='ypjax-link')]
158 class_='ypjax-link')]
159 paths_l = paths.split('/')
159 paths_l = paths.split('/')
160 for cnt, p in enumerate(paths_l):
160 for cnt, p in enumerate(paths_l):
161 if p != '':
161 if p != '':
162 url_l.append(link_to(p,
162 url_l.append(link_to(p,
163 url('files_home',
163 url('files_home',
164 repo_name=repo_name,
164 repo_name=repo_name,
165 revision=rev,
165 revision=rev,
166 f_path='/'.join(paths_l[:cnt + 1])
166 f_path='/'.join(paths_l[:cnt + 1])
167 ),
167 ),
168 class_='ypjax-link'
168 class_='ypjax-link'
169 )
169 )
170 )
170 )
171
171
172 return literal('/'.join(url_l))
172 return literal('/'.join(url_l))
173
173
174 files_breadcrumbs = _FilesBreadCrumbs()
174 files_breadcrumbs = _FilesBreadCrumbs()
175
175
176
176
177 class CodeHtmlFormatter(HtmlFormatter):
177 class CodeHtmlFormatter(HtmlFormatter):
178 """
178 """
179 My code Html Formatter for source codes
179 My code Html Formatter for source codes
180 """
180 """
181
181
182 def wrap(self, source, outfile):
182 def wrap(self, source, outfile):
183 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
183 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
184
184
185 def _wrap_code(self, source):
185 def _wrap_code(self, source):
186 for cnt, it in enumerate(source):
186 for cnt, it in enumerate(source):
187 i, t = it
187 i, t = it
188 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
188 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
189 yield i, t
189 yield i, t
190
190
191 def _wrap_tablelinenos(self, inner):
191 def _wrap_tablelinenos(self, inner):
192 dummyoutfile = StringIO.StringIO()
192 dummyoutfile = StringIO.StringIO()
193 lncount = 0
193 lncount = 0
194 for t, line in inner:
194 for t, line in inner:
195 if t:
195 if t:
196 lncount += 1
196 lncount += 1
197 dummyoutfile.write(line)
197 dummyoutfile.write(line)
198
198
199 fl = self.linenostart
199 fl = self.linenostart
200 mw = len(str(lncount + fl - 1))
200 mw = len(str(lncount + fl - 1))
201 sp = self.linenospecial
201 sp = self.linenospecial
202 st = self.linenostep
202 st = self.linenostep
203 la = self.lineanchors
203 la = self.lineanchors
204 aln = self.anchorlinenos
204 aln = self.anchorlinenos
205 nocls = self.noclasses
205 nocls = self.noclasses
206 if sp:
206 if sp:
207 lines = []
207 lines = []
208
208
209 for i in range(fl, fl + lncount):
209 for i in range(fl, fl + lncount):
210 if i % st == 0:
210 if i % st == 0:
211 if i % sp == 0:
211 if i % sp == 0:
212 if aln:
212 if aln:
213 lines.append('<a href="#%s%d" class="special">%*d</a>' %
213 lines.append('<a href="#%s%d" class="special">%*d</a>' %
214 (la, i, mw, i))
214 (la, i, mw, i))
215 else:
215 else:
216 lines.append('<span class="special">%*d</span>' % (mw, i))
216 lines.append('<span class="special">%*d</span>' % (mw, i))
217 else:
217 else:
218 if aln:
218 if aln:
219 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
219 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
220 else:
220 else:
221 lines.append('%*d' % (mw, i))
221 lines.append('%*d' % (mw, i))
222 else:
222 else:
223 lines.append('')
223 lines.append('')
224 ls = '\n'.join(lines)
224 ls = '\n'.join(lines)
225 else:
225 else:
226 lines = []
226 lines = []
227 for i in range(fl, fl + lncount):
227 for i in range(fl, fl + lncount):
228 if i % st == 0:
228 if i % st == 0:
229 if aln:
229 if aln:
230 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
230 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
231 else:
231 else:
232 lines.append('%*d' % (mw, i))
232 lines.append('%*d' % (mw, i))
233 else:
233 else:
234 lines.append('')
234 lines.append('')
235 ls = '\n'.join(lines)
235 ls = '\n'.join(lines)
236
236
237 # in case you wonder about the seemingly redundant <div> here: since the
237 # in case you wonder about the seemingly redundant <div> here: since the
238 # content in the other cell also is wrapped in a div, some browsers in
238 # content in the other cell also is wrapped in a div, some browsers in
239 # some configurations seem to mess up the formatting...
239 # some configurations seem to mess up the formatting...
240 if nocls:
240 if nocls:
241 yield 0, ('<table class="%stable">' % self.cssclass +
241 yield 0, ('<table class="%stable">' % self.cssclass +
242 '<tr><td><div class="linenodiv" '
242 '<tr><td><div class="linenodiv" '
243 'style="background-color: #f0f0f0; padding-right: 10px">'
243 'style="background-color: #f0f0f0; padding-right: 10px">'
244 '<pre style="line-height: 125%">' +
244 '<pre style="line-height: 125%">' +
245 ls + '</pre></div></td><td id="hlcode" class="code">')
245 ls + '</pre></div></td><td id="hlcode" class="code">')
246 else:
246 else:
247 yield 0, ('<table class="%stable">' % self.cssclass +
247 yield 0, ('<table class="%stable">' % self.cssclass +
248 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
248 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
249 ls + '</pre></div></td><td id="hlcode" class="code">')
249 ls + '</pre></div></td><td id="hlcode" class="code">')
250 yield 0, dummyoutfile.getvalue()
250 yield 0, dummyoutfile.getvalue()
251 yield 0, '</td></tr></table>'
251 yield 0, '</td></tr></table>'
252
252
253
253
254 def pygmentize(filenode, **kwargs):
254 def pygmentize(filenode, **kwargs):
255 """pygmentize function using pygments
255 """pygmentize function using pygments
256
256
257 :param filenode:
257 :param filenode:
258 """
258 """
259
259
260 return literal(code_highlight(filenode.content,
260 return literal(code_highlight(filenode.content,
261 filenode.lexer, CodeHtmlFormatter(**kwargs)))
261 filenode.lexer, CodeHtmlFormatter(**kwargs)))
262
262
263
263
264 def pygmentize_annotation(repo_name, filenode, **kwargs):
264 def pygmentize_annotation(repo_name, filenode, **kwargs):
265 """
265 """
266 pygmentize function for annotation
266 pygmentize function for annotation
267
267
268 :param filenode:
268 :param filenode:
269 """
269 """
270
270
271 color_dict = {}
271 color_dict = {}
272
272
273 def gen_color(n=10000):
273 def gen_color(n=10000):
274 """generator for getting n of evenly distributed colors using
274 """generator for getting n of evenly distributed colors using
275 hsv color and golden ratio. It always return same order of colors
275 hsv color and golden ratio. It always return same order of colors
276
276
277 :returns: RGB tuple
277 :returns: RGB tuple
278 """
278 """
279
279
280 def hsv_to_rgb(h, s, v):
280 def hsv_to_rgb(h, s, v):
281 if s == 0.0:
281 if s == 0.0:
282 return v, v, v
282 return v, v, v
283 i = int(h * 6.0) # XXX assume int() truncates!
283 i = int(h * 6.0) # XXX assume int() truncates!
284 f = (h * 6.0) - i
284 f = (h * 6.0) - i
285 p = v * (1.0 - s)
285 p = v * (1.0 - s)
286 q = v * (1.0 - s * f)
286 q = v * (1.0 - s * f)
287 t = v * (1.0 - s * (1.0 - f))
287 t = v * (1.0 - s * (1.0 - f))
288 i = i % 6
288 i = i % 6
289 if i == 0:
289 if i == 0:
290 return v, t, p
290 return v, t, p
291 if i == 1:
291 if i == 1:
292 return q, v, p
292 return q, v, p
293 if i == 2:
293 if i == 2:
294 return p, v, t
294 return p, v, t
295 if i == 3:
295 if i == 3:
296 return p, q, v
296 return p, q, v
297 if i == 4:
297 if i == 4:
298 return t, p, v
298 return t, p, v
299 if i == 5:
299 if i == 5:
300 return v, p, q
300 return v, p, q
301
301
302 golden_ratio = 0.618033988749895
302 golden_ratio = 0.618033988749895
303 h = 0.22717784590367374
303 h = 0.22717784590367374
304
304
305 for _ in xrange(n):
305 for _ in xrange(n):
306 h += golden_ratio
306 h += golden_ratio
307 h %= 1
307 h %= 1
308 HSV_tuple = [h, 0.95, 0.95]
308 HSV_tuple = [h, 0.95, 0.95]
309 RGB_tuple = hsv_to_rgb(*HSV_tuple)
309 RGB_tuple = hsv_to_rgb(*HSV_tuple)
310 yield map(lambda x: str(int(x * 256)), RGB_tuple)
310 yield map(lambda x: str(int(x * 256)), RGB_tuple)
311
311
312 cgenerator = gen_color()
312 cgenerator = gen_color()
313
313
314 def get_color_string(cs):
314 def get_color_string(cs):
315 if cs in color_dict:
315 if cs in color_dict:
316 col = color_dict[cs]
316 col = color_dict[cs]
317 else:
317 else:
318 col = color_dict[cs] = cgenerator.next()
318 col = color_dict[cs] = cgenerator.next()
319 return "color: rgb(%s)! important;" % (', '.join(col))
319 return "color: rgb(%s)! important;" % (', '.join(col))
320
320
321 def url_func(repo_name):
321 def url_func(repo_name):
322
322
323 def _url_func(changeset):
323 def _url_func(changeset):
324 author = changeset.author
324 author = changeset.author
325 date = changeset.date
325 date = changeset.date
326 message = tooltip(changeset.message)
326 message = tooltip(changeset.message)
327
327
328 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
328 tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>"
329 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
329 " %s<br/><b>Date:</b> %s</b><br/><b>Message:"
330 "</b> %s<br/></div>")
330 "</b> %s<br/></div>")
331
331
332 tooltip_html = tooltip_html % (author, date, message)
332 tooltip_html = tooltip_html % (author, date, message)
333 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
333 lnk_format = '%5s:%s' % ('r%s' % changeset.revision,
334 short_id(changeset.raw_id))
334 short_id(changeset.raw_id))
335 uri = link_to(
335 uri = link_to(
336 lnk_format,
336 lnk_format,
337 url('changeset_home', repo_name=repo_name,
337 url('changeset_home', repo_name=repo_name,
338 revision=changeset.raw_id),
338 revision=changeset.raw_id),
339 style=get_color_string(changeset.raw_id),
339 style=get_color_string(changeset.raw_id),
340 class_='tooltip',
340 class_='tooltip',
341 title=tooltip_html
341 title=tooltip_html
342 )
342 )
343
343
344 uri += '\n'
344 uri += '\n'
345 return uri
345 return uri
346 return _url_func
346 return _url_func
347
347
348 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
348 return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs))
349
349
350
350
351 def is_following_repo(repo_name, user_id):
351 def is_following_repo(repo_name, user_id):
352 from rhodecode.model.scm import ScmModel
352 from rhodecode.model.scm import ScmModel
353 return ScmModel().is_following_repo(repo_name, user_id)
353 return ScmModel().is_following_repo(repo_name, user_id)
354
354
355 flash = _Flash()
355 flash = _Flash()
356
356
357 #==============================================================================
357 #==============================================================================
358 # SCM FILTERS available via h.
358 # SCM FILTERS available via h.
359 #==============================================================================
359 #==============================================================================
360 from rhodecode.lib.vcs.utils import author_name, author_email
360 from rhodecode.lib.vcs.utils import author_name, author_email
361 from rhodecode.lib.utils2 import credentials_filter, age as _age
361 from rhodecode.lib.utils2 import credentials_filter, age as _age
362 from rhodecode.model.db import User, ChangesetStatus
362 from rhodecode.model.db import User, ChangesetStatus
363
363
364 age = lambda x: _age(x)
364 age = lambda x: _age(x)
365 capitalize = lambda x: x.capitalize()
365 capitalize = lambda x: x.capitalize()
366 email = author_email
366 email = author_email
367 short_id = lambda x: x[:12]
367 short_id = lambda x: x[:12]
368 hide_credentials = lambda x: ''.join(credentials_filter(x))
368 hide_credentials = lambda x: ''.join(credentials_filter(x))
369
369
370
370
371 def fmt_date(date):
371 def fmt_date(date):
372 if date:
372 if date:
373 _fmt = _(u"%a, %d %b %Y %H:%M:%S").encode('utf8')
373 _fmt = _(u"%a, %d %b %Y %H:%M:%S").encode('utf8')
374 return date.strftime(_fmt).decode('utf8')
374 return date.strftime(_fmt).decode('utf8')
375
375
376 return ""
376 return ""
377
377
378
378
379 def is_git(repository):
379 def is_git(repository):
380 if hasattr(repository, 'alias'):
380 if hasattr(repository, 'alias'):
381 _type = repository.alias
381 _type = repository.alias
382 elif hasattr(repository, 'repo_type'):
382 elif hasattr(repository, 'repo_type'):
383 _type = repository.repo_type
383 _type = repository.repo_type
384 else:
384 else:
385 _type = repository
385 _type = repository
386 return _type == 'git'
386 return _type == 'git'
387
387
388
388
389 def is_hg(repository):
389 def is_hg(repository):
390 if hasattr(repository, 'alias'):
390 if hasattr(repository, 'alias'):
391 _type = repository.alias
391 _type = repository.alias
392 elif hasattr(repository, 'repo_type'):
392 elif hasattr(repository, 'repo_type'):
393 _type = repository.repo_type
393 _type = repository.repo_type
394 else:
394 else:
395 _type = repository
395 _type = repository
396 return _type == 'hg'
396 return _type == 'hg'
397
397
398
398
399 def email_or_none(author):
399 def email_or_none(author):
400 # extract email from the commit string
400 # extract email from the commit string
401 _email = email(author)
401 _email = email(author)
402 if _email != '':
402 if _email != '':
403 # check it against RhodeCode database, and use the MAIN email for this
403 # check it against RhodeCode database, and use the MAIN email for this
404 # user
404 # user
405 user = User.get_by_email(_email, case_insensitive=True, cache=True)
405 user = User.get_by_email(_email, case_insensitive=True, cache=True)
406 if user is not None:
406 if user is not None:
407 return user.email
407 return user.email
408 return _email
408 return _email
409
409
410 # See if it contains a username we can get an email from
410 # See if it contains a username we can get an email from
411 user = User.get_by_username(author_name(author), case_insensitive=True,
411 user = User.get_by_username(author_name(author), case_insensitive=True,
412 cache=True)
412 cache=True)
413 if user is not None:
413 if user is not None:
414 return user.email
414 return user.email
415
415
416 # No valid email, not a valid user in the system, none!
416 # No valid email, not a valid user in the system, none!
417 return None
417 return None
418
418
419
419
420 def person(author, show_attr="username_and_name"):
420 def person(author, show_attr="username_and_name"):
421 # attr to return from fetched user
421 # attr to return from fetched user
422 person_getter = lambda usr: getattr(usr, show_attr)
422 person_getter = lambda usr: getattr(usr, show_attr)
423
423
424 # Valid email in the attribute passed, see if they're in the system
424 # Valid email in the attribute passed, see if they're in the system
425 _email = email(author)
425 _email = email(author)
426 if _email != '':
426 if _email != '':
427 user = User.get_by_email(_email, case_insensitive=True, cache=True)
427 user = User.get_by_email(_email, case_insensitive=True, cache=True)
428 if user is not None:
428 if user is not None:
429 return person_getter(user)
429 return person_getter(user)
430 return _email
430 return _email
431
431
432 # Maybe it's a username?
432 # Maybe it's a username?
433 _author = author_name(author)
433 _author = author_name(author)
434 user = User.get_by_username(_author, case_insensitive=True,
434 user = User.get_by_username(_author, case_insensitive=True,
435 cache=True)
435 cache=True)
436 if user is not None:
436 if user is not None:
437 return person_getter(user)
437 return person_getter(user)
438
438
439 # Still nothing? Just pass back the author name then
439 # Still nothing? Just pass back the author name then
440 return _author
440 return _author
441
441
442
442
443 def person_by_id(id_, show_attr="username_and_name"):
443 def person_by_id(id_, show_attr="username_and_name"):
444 # attr to return from fetched user
444 # attr to return from fetched user
445 person_getter = lambda usr: getattr(usr, show_attr)
445 person_getter = lambda usr: getattr(usr, show_attr)
446
446
447 #maybe it's an ID ?
447 #maybe it's an ID ?
448 if str(id_).isdigit() or isinstance(id_, int):
448 if str(id_).isdigit() or isinstance(id_, int):
449 id_ = int(id_)
449 id_ = int(id_)
450 user = User.get(id_)
450 user = User.get(id_)
451 if user is not None:
451 if user is not None:
452 return person_getter(user)
452 return person_getter(user)
453 return id_
453 return id_
454
454
455
455
456 def desc_stylize(value):
456 def desc_stylize(value):
457 """
457 """
458 converts tags from value into html equivalent
458 converts tags from value into html equivalent
459
459
460 :param value:
460 :param value:
461 """
461 """
462 value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
462 value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
463 '<div class="metatag" tag="see">see =&gt; \\1 </div>', value)
463 '<div class="metatag" tag="see">see =&gt; \\1 </div>', value)
464 value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
464 value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]',
465 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
465 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value)
466 value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z\-\/]*)\]',
466 value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z\-\/]*)\]',
467 '<div class="metatag" tag="\\1">\\1 =&gt; <a href="/\\2">\\2</a></div>', value)
467 '<div class="metatag" tag="\\1">\\1 =&gt; <a href="/\\2">\\2</a></div>', value)
468 value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]',
468 value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]',
469 '<div class="metatag" tag="lang">\\2</div>', value)
469 '<div class="metatag" tag="lang">\\2</div>', value)
470 value = re.sub(r'\[([a-z]+)\]',
470 value = re.sub(r'\[([a-z]+)\]',
471 '<div class="metatag" tag="\\1">\\1</div>', value)
471 '<div class="metatag" tag="\\1">\\1</div>', value)
472
472
473 return value
473 return value
474
474
475
475
476 def bool2icon(value):
476 def bool2icon(value):
477 """Returns True/False values represented as small html image of true/false
477 """Returns True/False values represented as small html image of true/false
478 icons
478 icons
479
479
480 :param value: bool value
480 :param value: bool value
481 """
481 """
482
482
483 if value is True:
483 if value is True:
484 return HTML.tag('img', src=url("/images/icons/accept.png"),
484 return HTML.tag('img', src=url("/images/icons/accept.png"),
485 alt=_('True'))
485 alt=_('True'))
486
486
487 if value is False:
487 if value is False:
488 return HTML.tag('img', src=url("/images/icons/cancel.png"),
488 return HTML.tag('img', src=url("/images/icons/cancel.png"),
489 alt=_('False'))
489 alt=_('False'))
490
490
491 return value
491 return value
492
492
493
493
494 def action_parser(user_log, feed=False, parse_cs=False):
494 def action_parser(user_log, feed=False, parse_cs=False):
495 """
495 """
496 This helper will action_map the specified string action into translated
496 This helper will action_map the specified string action into translated
497 fancy names with icons and links
497 fancy names with icons and links
498
498
499 :param user_log: user log instance
499 :param user_log: user log instance
500 :param feed: use output for feeds (no html and fancy icons)
500 :param feed: use output for feeds (no html and fancy icons)
501 :param parse_cs: parse Changesets into VCS instances
501 :param parse_cs: parse Changesets into VCS instances
502 """
502 """
503
503
504 action = user_log.action
504 action = user_log.action
505 action_params = ' '
505 action_params = ' '
506
506
507 x = action.split(':')
507 x = action.split(':')
508
508
509 if len(x) > 1:
509 if len(x) > 1:
510 action, action_params = x
510 action, action_params = x
511
511
512 def get_cs_links():
512 def get_cs_links():
513 revs_limit = 3 # display this amount always
513 revs_limit = 3 # display this amount always
514 revs_top_limit = 50 # show upto this amount of changesets hidden
514 revs_top_limit = 50 # show upto this amount of changesets hidden
515 revs_ids = action_params.split(',')
515 revs_ids = action_params.split(',')
516 deleted = user_log.repository is None
516 deleted = user_log.repository is None
517 if deleted:
517 if deleted:
518 return ','.join(revs_ids)
518 return ','.join(revs_ids)
519
519
520 repo_name = user_log.repository.repo_name
520 repo_name = user_log.repository.repo_name
521
521
522 def lnk(rev, repo_name):
522 def lnk(rev, repo_name):
523 if isinstance(rev, BaseChangeset) or isinstance(rev, AttributeDict):
523 if isinstance(rev, BaseChangeset) or isinstance(rev, AttributeDict):
524 lazy_cs = True
524 lazy_cs = True
525 if getattr(rev, 'op', None) and getattr(rev, 'ref_name', None):
525 if getattr(rev, 'op', None) and getattr(rev, 'ref_name', None):
526 lazy_cs = False
526 lazy_cs = False
527 lbl = '?'
527 lbl = '?'
528 if rev.op == 'delete_branch':
528 if rev.op == 'delete_branch':
529 lbl = '%s' % _('Deleted branch: %s') % rev.ref_name
529 lbl = '%s' % _('Deleted branch: %s') % rev.ref_name
530 title = ''
530 title = ''
531 elif rev.op == 'tag':
531 elif rev.op == 'tag':
532 lbl = '%s' % _('Created tag: %s') % rev.ref_name
532 lbl = '%s' % _('Created tag: %s') % rev.ref_name
533 title = ''
533 title = ''
534 _url = '#'
534 _url = '#'
535
535
536 else:
536 else:
537 lbl = '%s' % (rev.short_id[:8])
537 lbl = '%s' % (rev.short_id[:8])
538 _url = url('changeset_home', repo_name=repo_name,
538 _url = url('changeset_home', repo_name=repo_name,
539 revision=rev.raw_id)
539 revision=rev.raw_id)
540 title = tooltip(rev.message)
540 title = tooltip(rev.message)
541 else:
541 else:
542 ## changeset cannot be found/striped/removed etc.
542 ## changeset cannot be found/striped/removed etc.
543 lbl = ('%s' % rev)[:12]
543 lbl = ('%s' % rev)[:12]
544 _url = '#'
544 _url = '#'
545 title = _('Changeset not found')
545 title = _('Changeset not found')
546 if parse_cs:
546 if parse_cs:
547 return link_to(lbl, _url, title=title, class_='tooltip')
547 return link_to(lbl, _url, title=title, class_='tooltip')
548 return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name,
548 return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name,
549 class_='lazy-cs' if lazy_cs else '')
549 class_='lazy-cs' if lazy_cs else '')
550
550
551 revs = []
551 revs = []
552 if len(filter(lambda v: v != '', revs_ids)) > 0:
552 if len(filter(lambda v: v != '', revs_ids)) > 0:
553 repo = None
553 repo = None
554 for rev in revs_ids[:revs_top_limit]:
554 for rev in revs_ids[:revs_top_limit]:
555 _op = _name = None
555 _op = _name = None
556 if len(rev.split('=>')) == 2:
556 if len(rev.split('=>')) == 2:
557 _op, _name = rev.split('=>')
557 _op, _name = rev.split('=>')
558
558
559 # we want parsed changesets, or new log store format is bad
559 # we want parsed changesets, or new log store format is bad
560 if parse_cs:
560 if parse_cs:
561 try:
561 try:
562 if repo is None:
562 if repo is None:
563 repo = user_log.repository.scm_instance
563 repo = user_log.repository.scm_instance
564 _rev = repo.get_changeset(rev)
564 _rev = repo.get_changeset(rev)
565 revs.append(_rev)
565 revs.append(_rev)
566 except ChangesetDoesNotExistError:
566 except ChangesetDoesNotExistError:
567 log.error('cannot find revision %s in this repo' % rev)
567 log.error('cannot find revision %s in this repo' % rev)
568 revs.append(rev)
568 revs.append(rev)
569 continue
569 continue
570 else:
570 else:
571 _rev = AttributeDict({
571 _rev = AttributeDict({
572 'short_id': rev[:12],
572 'short_id': rev[:12],
573 'raw_id': rev,
573 'raw_id': rev,
574 'message': '',
574 'message': '',
575 'op': _op,
575 'op': _op,
576 'ref_name': _name
576 'ref_name': _name
577 })
577 })
578 revs.append(_rev)
578 revs.append(_rev)
579 cs_links = []
579 cs_links = []
580 cs_links.append(" " + ', '.join(
580 cs_links.append(" " + ', '.join(
581 [lnk(rev, repo_name) for rev in revs[:revs_limit]]
581 [lnk(rev, repo_name) for rev in revs[:revs_limit]]
582 )
582 )
583 )
583 )
584
584
585 compare_view = (
585 compare_view = (
586 ' <div class="compare_view tooltip" title="%s">'
586 ' <div class="compare_view tooltip" title="%s">'
587 '<a href="%s">%s</a> </div>' % (
587 '<a href="%s">%s</a> </div>' % (
588 _('Show all combined changesets %s->%s') % (
588 _('Show all combined changesets %s->%s') % (
589 revs_ids[0][:12], revs_ids[-1][:12]
589 revs_ids[0][:12], revs_ids[-1][:12]
590 ),
590 ),
591 url('changeset_home', repo_name=repo_name,
591 url('changeset_home', repo_name=repo_name,
592 revision='%s...%s' % (revs_ids[0], revs_ids[-1])
592 revision='%s...%s' % (revs_ids[0], revs_ids[-1])
593 ),
593 ),
594 _('compare view')
594 _('compare view')
595 )
595 )
596 )
596 )
597
597
598 # if we have exactly one more than normally displayed
598 # if we have exactly one more than normally displayed
599 # just display it, takes less space than displaying
599 # just display it, takes less space than displaying
600 # "and 1 more revisions"
600 # "and 1 more revisions"
601 if len(revs_ids) == revs_limit + 1:
601 if len(revs_ids) == revs_limit + 1:
602 rev = revs[revs_limit]
602 rev = revs[revs_limit]
603 cs_links.append(", " + lnk(rev, repo_name))
603 cs_links.append(", " + lnk(rev, repo_name))
604
604
605 # hidden-by-default ones
605 # hidden-by-default ones
606 if len(revs_ids) > revs_limit + 1:
606 if len(revs_ids) > revs_limit + 1:
607 uniq_id = revs_ids[0]
607 uniq_id = revs_ids[0]
608 html_tmpl = (
608 html_tmpl = (
609 '<span> %s <a class="show_more" id="_%s" '
609 '<span> %s <a class="show_more" id="_%s" '
610 'href="#more">%s</a> %s</span>'
610 'href="#more">%s</a> %s</span>'
611 )
611 )
612 if not feed:
612 if not feed:
613 cs_links.append(html_tmpl % (
613 cs_links.append(html_tmpl % (
614 _('and'),
614 _('and'),
615 uniq_id, _('%s more') % (len(revs_ids) - revs_limit),
615 uniq_id, _('%s more') % (len(revs_ids) - revs_limit),
616 _('revisions')
616 _('revisions')
617 )
617 )
618 )
618 )
619
619
620 if not feed:
620 if not feed:
621 html_tmpl = '<span id="%s" style="display:none">, %s </span>'
621 html_tmpl = '<span id="%s" style="display:none">, %s </span>'
622 else:
622 else:
623 html_tmpl = '<span id="%s"> %s </span>'
623 html_tmpl = '<span id="%s"> %s </span>'
624
624
625 morelinks = ', '.join(
625 morelinks = ', '.join(
626 [lnk(rev, repo_name) for rev in revs[revs_limit:]]
626 [lnk(rev, repo_name) for rev in revs[revs_limit:]]
627 )
627 )
628
628
629 if len(revs_ids) > revs_top_limit:
629 if len(revs_ids) > revs_top_limit:
630 morelinks += ', ...'
630 morelinks += ', ...'
631
631
632 cs_links.append(html_tmpl % (uniq_id, morelinks))
632 cs_links.append(html_tmpl % (uniq_id, morelinks))
633 if len(revs) > 1:
633 if len(revs) > 1:
634 cs_links.append(compare_view)
634 cs_links.append(compare_view)
635 return ''.join(cs_links)
635 return ''.join(cs_links)
636
636
637 def get_fork_name():
637 def get_fork_name():
638 repo_name = action_params
638 repo_name = action_params
639 _url = url('summary_home', repo_name=repo_name)
639 _url = url('summary_home', repo_name=repo_name)
640 return _('fork name %s') % link_to(action_params, _url)
640 return _('fork name %s') % link_to(action_params, _url)
641
641
642 def get_user_name():
642 def get_user_name():
643 user_name = action_params
643 user_name = action_params
644 return user_name
644 return user_name
645
645
646 def get_users_group():
646 def get_users_group():
647 group_name = action_params
647 group_name = action_params
648 return group_name
648 return group_name
649
649
650 def get_pull_request():
650 def get_pull_request():
651 pull_request_id = action_params
651 pull_request_id = action_params
652 repo_name = user_log.repository.repo_name
652 deleted = user_log.repository is None
653 if deleted:
654 repo_name = user_log.repository_name
655 else:
656 repo_name = user_log.repository.repo_name
653 return link_to(_('Pull request #%s') % pull_request_id,
657 return link_to(_('Pull request #%s') % pull_request_id,
654 url('pullrequest_show', repo_name=repo_name,
658 url('pullrequest_show', repo_name=repo_name,
655 pull_request_id=pull_request_id))
659 pull_request_id=pull_request_id))
656
660
657 # action : translated str, callback(extractor), icon
661 # action : translated str, callback(extractor), icon
658 action_map = {
662 action_map = {
659 'user_deleted_repo': (_('[deleted] repository'),
663 'user_deleted_repo': (_('[deleted] repository'),
660 None, 'database_delete.png'),
664 None, 'database_delete.png'),
661 'user_created_repo': (_('[created] repository'),
665 'user_created_repo': (_('[created] repository'),
662 None, 'database_add.png'),
666 None, 'database_add.png'),
663 'user_created_fork': (_('[created] repository as fork'),
667 'user_created_fork': (_('[created] repository as fork'),
664 None, 'arrow_divide.png'),
668 None, 'arrow_divide.png'),
665 'user_forked_repo': (_('[forked] repository'),
669 'user_forked_repo': (_('[forked] repository'),
666 get_fork_name, 'arrow_divide.png'),
670 get_fork_name, 'arrow_divide.png'),
667 'user_updated_repo': (_('[updated] repository'),
671 'user_updated_repo': (_('[updated] repository'),
668 None, 'database_edit.png'),
672 None, 'database_edit.png'),
669 'admin_deleted_repo': (_('[delete] repository'),
673 'admin_deleted_repo': (_('[delete] repository'),
670 None, 'database_delete.png'),
674 None, 'database_delete.png'),
671 'admin_created_repo': (_('[created] repository'),
675 'admin_created_repo': (_('[created] repository'),
672 None, 'database_add.png'),
676 None, 'database_add.png'),
673 'admin_forked_repo': (_('[forked] repository'),
677 'admin_forked_repo': (_('[forked] repository'),
674 None, 'arrow_divide.png'),
678 None, 'arrow_divide.png'),
675 'admin_updated_repo': (_('[updated] repository'),
679 'admin_updated_repo': (_('[updated] repository'),
676 None, 'database_edit.png'),
680 None, 'database_edit.png'),
677 'admin_created_user': (_('[created] user'),
681 'admin_created_user': (_('[created] user'),
678 get_user_name, 'user_add.png'),
682 get_user_name, 'user_add.png'),
679 'admin_updated_user': (_('[updated] user'),
683 'admin_updated_user': (_('[updated] user'),
680 get_user_name, 'user_edit.png'),
684 get_user_name, 'user_edit.png'),
681 'admin_created_users_group': (_('[created] users group'),
685 'admin_created_users_group': (_('[created] users group'),
682 get_users_group, 'group_add.png'),
686 get_users_group, 'group_add.png'),
683 'admin_updated_users_group': (_('[updated] users group'),
687 'admin_updated_users_group': (_('[updated] users group'),
684 get_users_group, 'group_edit.png'),
688 get_users_group, 'group_edit.png'),
685 'user_commented_revision': (_('[commented] on revision in repository'),
689 'user_commented_revision': (_('[commented] on revision in repository'),
686 get_cs_links, 'comment_add.png'),
690 get_cs_links, 'comment_add.png'),
687 'user_commented_pull_request': (_('[commented] on pull request for'),
691 'user_commented_pull_request': (_('[commented] on pull request for'),
688 get_pull_request, 'comment_add.png'),
692 get_pull_request, 'comment_add.png'),
689 'user_closed_pull_request': (_('[closed] pull request for'),
693 'user_closed_pull_request': (_('[closed] pull request for'),
690 get_pull_request, 'tick.png'),
694 get_pull_request, 'tick.png'),
691 'push': (_('[pushed] into'),
695 'push': (_('[pushed] into'),
692 get_cs_links, 'script_add.png'),
696 get_cs_links, 'script_add.png'),
693 'push_local': (_('[committed via RhodeCode] into repository'),
697 'push_local': (_('[committed via RhodeCode] into repository'),
694 get_cs_links, 'script_edit.png'),
698 get_cs_links, 'script_edit.png'),
695 'push_remote': (_('[pulled from remote] into repository'),
699 'push_remote': (_('[pulled from remote] into repository'),
696 get_cs_links, 'connect.png'),
700 get_cs_links, 'connect.png'),
697 'pull': (_('[pulled] from'),
701 'pull': (_('[pulled] from'),
698 None, 'down_16.png'),
702 None, 'down_16.png'),
699 'started_following_repo': (_('[started following] repository'),
703 'started_following_repo': (_('[started following] repository'),
700 None, 'heart_add.png'),
704 None, 'heart_add.png'),
701 'stopped_following_repo': (_('[stopped following] repository'),
705 'stopped_following_repo': (_('[stopped following] repository'),
702 None, 'heart_delete.png'),
706 None, 'heart_delete.png'),
703 }
707 }
704
708
705 action_str = action_map.get(action, action)
709 action_str = action_map.get(action, action)
706 if feed:
710 if feed:
707 action = action_str[0].replace('[', '').replace(']', '')
711 action = action_str[0].replace('[', '').replace(']', '')
708 else:
712 else:
709 action = action_str[0]\
713 action = action_str[0]\
710 .replace('[', '<span class="journal_highlight">')\
714 .replace('[', '<span class="journal_highlight">')\
711 .replace(']', '</span>')
715 .replace(']', '</span>')
712
716
713 action_params_func = lambda: ""
717 action_params_func = lambda: ""
714
718
715 if callable(action_str[1]):
719 if callable(action_str[1]):
716 action_params_func = action_str[1]
720 action_params_func = action_str[1]
717
721
718 def action_parser_icon():
722 def action_parser_icon():
719 action = user_log.action
723 action = user_log.action
720 action_params = None
724 action_params = None
721 x = action.split(':')
725 x = action.split(':')
722
726
723 if len(x) > 1:
727 if len(x) > 1:
724 action, action_params = x
728 action, action_params = x
725
729
726 tmpl = """<img src="%s%s" alt="%s"/>"""
730 tmpl = """<img src="%s%s" alt="%s"/>"""
727 ico = action_map.get(action, ['', '', ''])[2]
731 ico = action_map.get(action, ['', '', ''])[2]
728 return literal(tmpl % ((url('/images/icons/')), ico, action))
732 return literal(tmpl % ((url('/images/icons/')), ico, action))
729
733
730 # returned callbacks we need to call to get
734 # returned callbacks we need to call to get
731 return [lambda: literal(action), action_params_func, action_parser_icon]
735 return [lambda: literal(action), action_params_func, action_parser_icon]
732
736
733
737
734
738
735 #==============================================================================
739 #==============================================================================
736 # PERMS
740 # PERMS
737 #==============================================================================
741 #==============================================================================
738 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
742 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
739 HasRepoPermissionAny, HasRepoPermissionAll
743 HasRepoPermissionAny, HasRepoPermissionAll
740
744
741
745
742 #==============================================================================
746 #==============================================================================
743 # GRAVATAR URL
747 # GRAVATAR URL
744 #==============================================================================
748 #==============================================================================
745
749
746 def gravatar_url(email_address, size=30):
750 def gravatar_url(email_address, size=30):
747 from pylons import url ## doh, we need to re-import url to mock it later
751 from pylons import url ## doh, we need to re-import url to mock it later
748 if(str2bool(config['app_conf'].get('use_gravatar')) and
752 if(str2bool(config['app_conf'].get('use_gravatar')) and
749 config['app_conf'].get('alternative_gravatar_url')):
753 config['app_conf'].get('alternative_gravatar_url')):
750 tmpl = config['app_conf'].get('alternative_gravatar_url', '')
754 tmpl = config['app_conf'].get('alternative_gravatar_url', '')
751 parsed_url = urlparse.urlparse(url.current(qualified=True))
755 parsed_url = urlparse.urlparse(url.current(qualified=True))
752 tmpl = tmpl.replace('{email}', email_address)\
756 tmpl = tmpl.replace('{email}', email_address)\
753 .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest()) \
757 .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest()) \
754 .replace('{netloc}', parsed_url.netloc)\
758 .replace('{netloc}', parsed_url.netloc)\
755 .replace('{scheme}', parsed_url.scheme)\
759 .replace('{scheme}', parsed_url.scheme)\
756 .replace('{size}', str(size))
760 .replace('{size}', str(size))
757 return tmpl
761 return tmpl
758
762
759 if (not str2bool(config['app_conf'].get('use_gravatar')) or
763 if (not str2bool(config['app_conf'].get('use_gravatar')) or
760 not email_address or email_address == 'anonymous@rhodecode.org'):
764 not email_address or email_address == 'anonymous@rhodecode.org'):
761 f = lambda a, l: min(l, key=lambda x: abs(x - a))
765 f = lambda a, l: min(l, key=lambda x: abs(x - a))
762 return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
766 return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))
763
767
764 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
768 ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme')
765 default = 'identicon'
769 default = 'identicon'
766 baseurl_nossl = "http://www.gravatar.com/avatar/"
770 baseurl_nossl = "http://www.gravatar.com/avatar/"
767 baseurl_ssl = "https://secure.gravatar.com/avatar/"
771 baseurl_ssl = "https://secure.gravatar.com/avatar/"
768 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
772 baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl
769
773
770 if isinstance(email_address, unicode):
774 if isinstance(email_address, unicode):
771 #hashlib crashes on unicode items
775 #hashlib crashes on unicode items
772 email_address = safe_str(email_address)
776 email_address = safe_str(email_address)
773 # construct the url
777 # construct the url
774 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
778 gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
775 gravatar_url += urllib.urlencode({'d': default, 's': str(size)})
779 gravatar_url += urllib.urlencode({'d': default, 's': str(size)})
776
780
777 return gravatar_url
781 return gravatar_url
778
782
779
783
780 #==============================================================================
784 #==============================================================================
781 # REPO PAGER, PAGER FOR REPOSITORY
785 # REPO PAGER, PAGER FOR REPOSITORY
782 #==============================================================================
786 #==============================================================================
783 class RepoPage(Page):
787 class RepoPage(Page):
784
788
785 def __init__(self, collection, page=1, items_per_page=20,
789 def __init__(self, collection, page=1, items_per_page=20,
786 item_count=None, url=None, **kwargs):
790 item_count=None, url=None, **kwargs):
787
791
788 """Create a "RepoPage" instance. special pager for paging
792 """Create a "RepoPage" instance. special pager for paging
789 repository
793 repository
790 """
794 """
791 self._url_generator = url
795 self._url_generator = url
792
796
793 # Safe the kwargs class-wide so they can be used in the pager() method
797 # Safe the kwargs class-wide so they can be used in the pager() method
794 self.kwargs = kwargs
798 self.kwargs = kwargs
795
799
796 # Save a reference to the collection
800 # Save a reference to the collection
797 self.original_collection = collection
801 self.original_collection = collection
798
802
799 self.collection = collection
803 self.collection = collection
800
804
801 # The self.page is the number of the current page.
805 # The self.page is the number of the current page.
802 # The first page has the number 1!
806 # The first page has the number 1!
803 try:
807 try:
804 self.page = int(page) # make it int() if we get it as a string
808 self.page = int(page) # make it int() if we get it as a string
805 except (ValueError, TypeError):
809 except (ValueError, TypeError):
806 self.page = 1
810 self.page = 1
807
811
808 self.items_per_page = items_per_page
812 self.items_per_page = items_per_page
809
813
810 # Unless the user tells us how many items the collections has
814 # Unless the user tells us how many items the collections has
811 # we calculate that ourselves.
815 # we calculate that ourselves.
812 if item_count is not None:
816 if item_count is not None:
813 self.item_count = item_count
817 self.item_count = item_count
814 else:
818 else:
815 self.item_count = len(self.collection)
819 self.item_count = len(self.collection)
816
820
817 # Compute the number of the first and last available page
821 # Compute the number of the first and last available page
818 if self.item_count > 0:
822 if self.item_count > 0:
819 self.first_page = 1
823 self.first_page = 1
820 self.page_count = int(math.ceil(float(self.item_count) /
824 self.page_count = int(math.ceil(float(self.item_count) /
821 self.items_per_page))
825 self.items_per_page))
822 self.last_page = self.first_page + self.page_count - 1
826 self.last_page = self.first_page + self.page_count - 1
823
827
824 # Make sure that the requested page number is the range of
828 # Make sure that the requested page number is the range of
825 # valid pages
829 # valid pages
826 if self.page > self.last_page:
830 if self.page > self.last_page:
827 self.page = self.last_page
831 self.page = self.last_page
828 elif self.page < self.first_page:
832 elif self.page < self.first_page:
829 self.page = self.first_page
833 self.page = self.first_page
830
834
831 # Note: the number of items on this page can be less than
835 # Note: the number of items on this page can be less than
832 # items_per_page if the last page is not full
836 # items_per_page if the last page is not full
833 self.first_item = max(0, (self.item_count) - (self.page *
837 self.first_item = max(0, (self.item_count) - (self.page *
834 items_per_page))
838 items_per_page))
835 self.last_item = ((self.item_count - 1) - items_per_page *
839 self.last_item = ((self.item_count - 1) - items_per_page *
836 (self.page - 1))
840 (self.page - 1))
837
841
838 self.items = list(self.collection[self.first_item:self.last_item + 1])
842 self.items = list(self.collection[self.first_item:self.last_item + 1])
839
843
840 # Links to previous and next page
844 # Links to previous and next page
841 if self.page > self.first_page:
845 if self.page > self.first_page:
842 self.previous_page = self.page - 1
846 self.previous_page = self.page - 1
843 else:
847 else:
844 self.previous_page = None
848 self.previous_page = None
845
849
846 if self.page < self.last_page:
850 if self.page < self.last_page:
847 self.next_page = self.page + 1
851 self.next_page = self.page + 1
848 else:
852 else:
849 self.next_page = None
853 self.next_page = None
850
854
851 # No items available
855 # No items available
852 else:
856 else:
853 self.first_page = None
857 self.first_page = None
854 self.page_count = 0
858 self.page_count = 0
855 self.last_page = None
859 self.last_page = None
856 self.first_item = None
860 self.first_item = None
857 self.last_item = None
861 self.last_item = None
858 self.previous_page = None
862 self.previous_page = None
859 self.next_page = None
863 self.next_page = None
860 self.items = []
864 self.items = []
861
865
862 # This is a subclass of the 'list' type. Initialise the list now.
866 # This is a subclass of the 'list' type. Initialise the list now.
863 list.__init__(self, reversed(self.items))
867 list.__init__(self, reversed(self.items))
864
868
865
869
866 def changed_tooltip(nodes):
870 def changed_tooltip(nodes):
867 """
871 """
868 Generates a html string for changed nodes in changeset page.
872 Generates a html string for changed nodes in changeset page.
869 It limits the output to 30 entries
873 It limits the output to 30 entries
870
874
871 :param nodes: LazyNodesGenerator
875 :param nodes: LazyNodesGenerator
872 """
876 """
873 if nodes:
877 if nodes:
874 pref = ': <br/> '
878 pref = ': <br/> '
875 suf = ''
879 suf = ''
876 if len(nodes) > 30:
880 if len(nodes) > 30:
877 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
881 suf = '<br/>' + _(' and %s more') % (len(nodes) - 30)
878 return literal(pref + '<br/> '.join([safe_unicode(x.path)
882 return literal(pref + '<br/> '.join([safe_unicode(x.path)
879 for x in nodes[:30]]) + suf)
883 for x in nodes[:30]]) + suf)
880 else:
884 else:
881 return ': ' + _('No Files')
885 return ': ' + _('No Files')
882
886
883
887
884 def repo_link(groups_and_repos, last_url=None):
888 def repo_link(groups_and_repos, last_url=None):
885 """
889 """
886 Makes a breadcrumbs link to repo within a group
890 Makes a breadcrumbs link to repo within a group
887 joins &raquo; on each group to create a fancy link
891 joins &raquo; on each group to create a fancy link
888
892
889 ex::
893 ex::
890 group >> subgroup >> repo
894 group >> subgroup >> repo
891
895
892 :param groups_and_repos:
896 :param groups_and_repos:
893 :param last_url:
897 :param last_url:
894 """
898 """
895 groups, repo_name = groups_and_repos
899 groups, repo_name = groups_and_repos
896 last_link = link_to(repo_name, last_url) if last_url else repo_name
900 last_link = link_to(repo_name, last_url) if last_url else repo_name
897
901
898 if not groups:
902 if not groups:
899 if last_url:
903 if last_url:
900 return last_link
904 return last_link
901 return repo_name
905 return repo_name
902 else:
906 else:
903 def make_link(group):
907 def make_link(group):
904 return link_to(group.name,
908 return link_to(group.name,
905 url('repos_group_home', group_name=group.group_name))
909 url('repos_group_home', group_name=group.group_name))
906 return literal(' &raquo; '.join(map(make_link, groups) + [last_link]))
910 return literal(' &raquo; '.join(map(make_link, groups) + [last_link]))
907
911
908
912
909 def fancy_file_stats(stats):
913 def fancy_file_stats(stats):
910 """
914 """
911 Displays a fancy two colored bar for number of added/deleted
915 Displays a fancy two colored bar for number of added/deleted
912 lines of code on file
916 lines of code on file
913
917
914 :param stats: two element list of added/deleted lines of code
918 :param stats: two element list of added/deleted lines of code
915 """
919 """
916 def cgen(l_type, a_v, d_v):
920 def cgen(l_type, a_v, d_v):
917 mapping = {'tr': 'top-right-rounded-corner-mid',
921 mapping = {'tr': 'top-right-rounded-corner-mid',
918 'tl': 'top-left-rounded-corner-mid',
922 'tl': 'top-left-rounded-corner-mid',
919 'br': 'bottom-right-rounded-corner-mid',
923 'br': 'bottom-right-rounded-corner-mid',
920 'bl': 'bottom-left-rounded-corner-mid'}
924 'bl': 'bottom-left-rounded-corner-mid'}
921 map_getter = lambda x: mapping[x]
925 map_getter = lambda x: mapping[x]
922
926
923 if l_type == 'a' and d_v:
927 if l_type == 'a' and d_v:
924 #case when added and deleted are present
928 #case when added and deleted are present
925 return ' '.join(map(map_getter, ['tl', 'bl']))
929 return ' '.join(map(map_getter, ['tl', 'bl']))
926
930
927 if l_type == 'a' and not d_v:
931 if l_type == 'a' and not d_v:
928 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
932 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
929
933
930 if l_type == 'd' and a_v:
934 if l_type == 'd' and a_v:
931 return ' '.join(map(map_getter, ['tr', 'br']))
935 return ' '.join(map(map_getter, ['tr', 'br']))
932
936
933 if l_type == 'd' and not a_v:
937 if l_type == 'd' and not a_v:
934 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
938 return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl']))
935
939
936 a, d = stats[0], stats[1]
940 a, d = stats[0], stats[1]
937 width = 100
941 width = 100
938
942
939 if a == 'b':
943 if a == 'b':
940 #binary mode
944 #binary mode
941 b_d = '<div class="bin%s %s" style="width:100%%">%s</div>' % (d, cgen('a', a_v='', d_v=0), 'bin')
945 b_d = '<div class="bin%s %s" style="width:100%%">%s</div>' % (d, cgen('a', a_v='', d_v=0), 'bin')
942 b_a = '<div class="bin1" style="width:0%%">%s</div>' % ('bin')
946 b_a = '<div class="bin1" style="width:0%%">%s</div>' % ('bin')
943 return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d))
947 return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d))
944
948
945 t = stats[0] + stats[1]
949 t = stats[0] + stats[1]
946 unit = float(width) / (t or 1)
950 unit = float(width) / (t or 1)
947
951
948 # needs > 9% of width to be visible or 0 to be hidden
952 # needs > 9% of width to be visible or 0 to be hidden
949 a_p = max(9, unit * a) if a > 0 else 0
953 a_p = max(9, unit * a) if a > 0 else 0
950 d_p = max(9, unit * d) if d > 0 else 0
954 d_p = max(9, unit * d) if d > 0 else 0
951 p_sum = a_p + d_p
955 p_sum = a_p + d_p
952
956
953 if p_sum > width:
957 if p_sum > width:
954 #adjust the percentage to be == 100% since we adjusted to 9
958 #adjust the percentage to be == 100% since we adjusted to 9
955 if a_p > d_p:
959 if a_p > d_p:
956 a_p = a_p - (p_sum - width)
960 a_p = a_p - (p_sum - width)
957 else:
961 else:
958 d_p = d_p - (p_sum - width)
962 d_p = d_p - (p_sum - width)
959
963
960 a_v = a if a > 0 else ''
964 a_v = a if a > 0 else ''
961 d_v = d if d > 0 else ''
965 d_v = d if d > 0 else ''
962
966
963 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
967 d_a = '<div class="added %s" style="width:%s%%">%s</div>' % (
964 cgen('a', a_v, d_v), a_p, a_v
968 cgen('a', a_v, d_v), a_p, a_v
965 )
969 )
966 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
970 d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % (
967 cgen('d', a_v, d_v), d_p, d_v
971 cgen('d', a_v, d_v), d_p, d_v
968 )
972 )
969 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
973 return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d))
970
974
971
975
972 def urlify_text(text_):
976 def urlify_text(text_):
973
977
974 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
978 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'''
975 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
979 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
976
980
977 def url_func(match_obj):
981 def url_func(match_obj):
978 url_full = match_obj.groups()[0]
982 url_full = match_obj.groups()[0]
979 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
983 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
980
984
981 return literal(url_pat.sub(url_func, text_))
985 return literal(url_pat.sub(url_func, text_))
982
986
983
987
984 def urlify_changesets(text_, repository):
988 def urlify_changesets(text_, repository):
985 """
989 """
986 Extract revision ids from changeset and make link from them
990 Extract revision ids from changeset and make link from them
987
991
988 :param text_:
992 :param text_:
989 :param repository:
993 :param repository:
990 """
994 """
991
995
992 URL_PAT = re.compile(r'([0-9a-fA-F]{12,})')
996 URL_PAT = re.compile(r'([0-9a-fA-F]{12,})')
993
997
994 def url_func(match_obj):
998 def url_func(match_obj):
995 rev = match_obj.groups()[0]
999 rev = match_obj.groups()[0]
996 pref = ''
1000 pref = ''
997 if match_obj.group().startswith(' '):
1001 if match_obj.group().startswith(' '):
998 pref = ' '
1002 pref = ' '
999 tmpl = (
1003 tmpl = (
1000 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1004 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1001 '%(rev)s'
1005 '%(rev)s'
1002 '</a>'
1006 '</a>'
1003 )
1007 )
1004 return tmpl % {
1008 return tmpl % {
1005 'pref': pref,
1009 'pref': pref,
1006 'cls': 'revision-link',
1010 'cls': 'revision-link',
1007 'url': url('changeset_home', repo_name=repository, revision=rev),
1011 'url': url('changeset_home', repo_name=repository, revision=rev),
1008 'rev': rev,
1012 'rev': rev,
1009 }
1013 }
1010
1014
1011 newtext = URL_PAT.sub(url_func, text_)
1015 newtext = URL_PAT.sub(url_func, text_)
1012
1016
1013 return newtext
1017 return newtext
1014
1018
1015
1019
1016 def urlify_commit(text_, repository=None, link_=None):
1020 def urlify_commit(text_, repository=None, link_=None):
1017 """
1021 """
1018 Parses given text message and makes proper links.
1022 Parses given text message and makes proper links.
1019 issues are linked to given issue-server, and rest is a changeset link
1023 issues are linked to given issue-server, and rest is a changeset link
1020 if link_ is given, in other case it's a plain text
1024 if link_ is given, in other case it's a plain text
1021
1025
1022 :param text_:
1026 :param text_:
1023 :param repository:
1027 :param repository:
1024 :param link_: changeset link
1028 :param link_: changeset link
1025 """
1029 """
1026 import traceback
1030 import traceback
1027
1031
1028 def escaper(string):
1032 def escaper(string):
1029 return string.replace('<', '&lt;').replace('>', '&gt;')
1033 return string.replace('<', '&lt;').replace('>', '&gt;')
1030
1034
1031 def linkify_others(t, l):
1035 def linkify_others(t, l):
1032 urls = re.compile(r'(\<a.*?\<\/a\>)',)
1036 urls = re.compile(r'(\<a.*?\<\/a\>)',)
1033 links = []
1037 links = []
1034 for e in urls.split(t):
1038 for e in urls.split(t):
1035 if not urls.match(e):
1039 if not urls.match(e):
1036 links.append('<a class="message-link" href="%s">%s</a>' % (l, e))
1040 links.append('<a class="message-link" href="%s">%s</a>' % (l, e))
1037 else:
1041 else:
1038 links.append(e)
1042 links.append(e)
1039
1043
1040 return ''.join(links)
1044 return ''.join(links)
1041
1045
1042 # urlify changesets - extrac revisions and make link out of them
1046 # urlify changesets - extrac revisions and make link out of them
1043 newtext = urlify_changesets(escaper(text_), repository)
1047 newtext = urlify_changesets(escaper(text_), repository)
1044
1048
1045 try:
1049 try:
1046 conf = config['app_conf']
1050 conf = config['app_conf']
1047
1051
1048 # allow multiple issue servers to be used
1052 # allow multiple issue servers to be used
1049 valid_indices = [
1053 valid_indices = [
1050 x.group(1)
1054 x.group(1)
1051 for x in map(lambda x: re.match(r'issue_pat(.*)', x), conf.keys())
1055 for x in map(lambda x: re.match(r'issue_pat(.*)', x), conf.keys())
1052 if x and 'issue_server_link%s' % x.group(1) in conf
1056 if x and 'issue_server_link%s' % x.group(1) in conf
1053 and 'issue_prefix%s' % x.group(1) in conf
1057 and 'issue_prefix%s' % x.group(1) in conf
1054 ]
1058 ]
1055
1059
1056 log.debug('found issue server suffixes `%s` during valuation of: %s'
1060 log.debug('found issue server suffixes `%s` during valuation of: %s'
1057 % (','.join(valid_indices), newtext))
1061 % (','.join(valid_indices), newtext))
1058
1062
1059 for pattern_index in valid_indices:
1063 for pattern_index in valid_indices:
1060 ISSUE_PATTERN = conf.get('issue_pat%s' % pattern_index)
1064 ISSUE_PATTERN = conf.get('issue_pat%s' % pattern_index)
1061 ISSUE_SERVER_LNK = conf.get('issue_server_link%s' % pattern_index)
1065 ISSUE_SERVER_LNK = conf.get('issue_server_link%s' % pattern_index)
1062 ISSUE_PREFIX = conf.get('issue_prefix%s' % pattern_index)
1066 ISSUE_PREFIX = conf.get('issue_prefix%s' % pattern_index)
1063
1067
1064 log.debug('pattern suffix `%s` PAT:%s SERVER_LINK:%s PREFIX:%s'
1068 log.debug('pattern suffix `%s` PAT:%s SERVER_LINK:%s PREFIX:%s'
1065 % (pattern_index, ISSUE_PATTERN, ISSUE_SERVER_LNK,
1069 % (pattern_index, ISSUE_PATTERN, ISSUE_SERVER_LNK,
1066 ISSUE_PREFIX))
1070 ISSUE_PREFIX))
1067
1071
1068 URL_PAT = re.compile(r'%s' % ISSUE_PATTERN)
1072 URL_PAT = re.compile(r'%s' % ISSUE_PATTERN)
1069
1073
1070 def url_func(match_obj):
1074 def url_func(match_obj):
1071 pref = ''
1075 pref = ''
1072 if match_obj.group().startswith(' '):
1076 if match_obj.group().startswith(' '):
1073 pref = ' '
1077 pref = ' '
1074
1078
1075 issue_id = ''.join(match_obj.groups())
1079 issue_id = ''.join(match_obj.groups())
1076 tmpl = (
1080 tmpl = (
1077 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1081 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1078 '%(issue-prefix)s%(id-repr)s'
1082 '%(issue-prefix)s%(id-repr)s'
1079 '</a>'
1083 '</a>'
1080 )
1084 )
1081 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
1085 url = ISSUE_SERVER_LNK.replace('{id}', issue_id)
1082 if repository:
1086 if repository:
1083 url = url.replace('{repo}', repository)
1087 url = url.replace('{repo}', repository)
1084 repo_name = repository.split(URL_SEP)[-1]
1088 repo_name = repository.split(URL_SEP)[-1]
1085 url = url.replace('{repo_name}', repo_name)
1089 url = url.replace('{repo_name}', repo_name)
1086
1090
1087 return tmpl % {
1091 return tmpl % {
1088 'pref': pref,
1092 'pref': pref,
1089 'cls': 'issue-tracker-link',
1093 'cls': 'issue-tracker-link',
1090 'url': url,
1094 'url': url,
1091 'id-repr': issue_id,
1095 'id-repr': issue_id,
1092 'issue-prefix': ISSUE_PREFIX,
1096 'issue-prefix': ISSUE_PREFIX,
1093 'serv': ISSUE_SERVER_LNK,
1097 'serv': ISSUE_SERVER_LNK,
1094 }
1098 }
1095 newtext = URL_PAT.sub(url_func, newtext)
1099 newtext = URL_PAT.sub(url_func, newtext)
1096 log.debug('processed prefix:`%s` => %s' % (pattern_index, newtext))
1100 log.debug('processed prefix:`%s` => %s' % (pattern_index, newtext))
1097
1101
1098 # if we actually did something above
1102 # if we actually did something above
1099 if link_:
1103 if link_:
1100 # wrap not links into final link => link_
1104 # wrap not links into final link => link_
1101 newtext = linkify_others(newtext, link_)
1105 newtext = linkify_others(newtext, link_)
1102 except:
1106 except:
1103 log.error(traceback.format_exc())
1107 log.error(traceback.format_exc())
1104 pass
1108 pass
1105
1109
1106 return literal(newtext)
1110 return literal(newtext)
1107
1111
1108
1112
1109 def rst(source):
1113 def rst(source):
1110 return literal('<div class="rst-block">%s</div>' %
1114 return literal('<div class="rst-block">%s</div>' %
1111 MarkupRenderer.rst(source))
1115 MarkupRenderer.rst(source))
1112
1116
1113
1117
1114 def rst_w_mentions(source):
1118 def rst_w_mentions(source):
1115 """
1119 """
1116 Wrapped rst renderer with @mention highlighting
1120 Wrapped rst renderer with @mention highlighting
1117
1121
1118 :param source:
1122 :param source:
1119 """
1123 """
1120 return literal('<div class="rst-block">%s</div>' %
1124 return literal('<div class="rst-block">%s</div>' %
1121 MarkupRenderer.rst_with_mentions(source))
1125 MarkupRenderer.rst_with_mentions(source))
1122
1126
1123
1127
1124 def changeset_status(repo, revision):
1128 def changeset_status(repo, revision):
1125 return ChangesetStatusModel().get_status(repo, revision)
1129 return ChangesetStatusModel().get_status(repo, revision)
1126
1130
1127
1131
1128 def changeset_status_lbl(changeset_status):
1132 def changeset_status_lbl(changeset_status):
1129 return dict(ChangesetStatus.STATUSES).get(changeset_status)
1133 return dict(ChangesetStatus.STATUSES).get(changeset_status)
1130
1134
1131
1135
1132 def get_permission_name(key):
1136 def get_permission_name(key):
1133 return dict(Permission.PERMS).get(key)
1137 return dict(Permission.PERMS).get(key)
@@ -1,742 +1,743 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.utils
3 rhodecode.lib.utils
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Utilities library for RhodeCode
6 Utilities library for RhodeCode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import re
27 import re
28 import logging
28 import logging
29 import datetime
29 import datetime
30 import traceback
30 import traceback
31 import paste
31 import paste
32 import beaker
32 import beaker
33 import tarfile
33 import tarfile
34 import shutil
34 import shutil
35 import decorator
35 import decorator
36 import warnings
36 import warnings
37 from os.path import abspath
37 from os.path import abspath
38 from os.path import dirname as dn, join as jn
38 from os.path import dirname as dn, join as jn
39
39
40 from paste.script.command import Command, BadCommand
40 from paste.script.command import Command, BadCommand
41
41
42 from mercurial import ui, config
42 from mercurial import ui, config
43
43
44 from webhelpers.text import collapse, remove_formatting, strip_tags
44 from webhelpers.text import collapse, remove_formatting, strip_tags
45
45
46 from rhodecode.lib.vcs import get_backend
46 from rhodecode.lib.vcs import get_backend
47 from rhodecode.lib.vcs.backends.base import BaseChangeset
47 from rhodecode.lib.vcs.backends.base import BaseChangeset
48 from rhodecode.lib.vcs.utils.lazy import LazyProperty
48 from rhodecode.lib.vcs.utils.lazy import LazyProperty
49 from rhodecode.lib.vcs.utils.helpers import get_scm
49 from rhodecode.lib.vcs.utils.helpers import get_scm
50 from rhodecode.lib.vcs.exceptions import VCSError
50 from rhodecode.lib.vcs.exceptions import VCSError
51
51
52 from rhodecode.lib.caching_query import FromCache
52 from rhodecode.lib.caching_query import FromCache
53
53
54 from rhodecode.model import meta
54 from rhodecode.model import meta
55 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
55 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
56 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
56 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
57 from rhodecode.model.meta import Session
57 from rhodecode.model.meta import Session
58 from rhodecode.model.repos_group import ReposGroupModel
58 from rhodecode.model.repos_group import ReposGroupModel
59 from rhodecode.lib.utils2 import safe_str, safe_unicode
59 from rhodecode.lib.utils2 import safe_str, safe_unicode
60 from rhodecode.lib.vcs.utils.fakemod import create_module
60 from rhodecode.lib.vcs.utils.fakemod import create_module
61
61
62 log = logging.getLogger(__name__)
62 log = logging.getLogger(__name__)
63
63
64 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
64 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
65
65
66
66
67 def recursive_replace(str_, replace=' '):
67 def recursive_replace(str_, replace=' '):
68 """
68 """
69 Recursive replace of given sign to just one instance
69 Recursive replace of given sign to just one instance
70
70
71 :param str_: given string
71 :param str_: given string
72 :param replace: char to find and replace multiple instances
72 :param replace: char to find and replace multiple instances
73
73
74 Examples::
74 Examples::
75 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
75 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
76 'Mighty-Mighty-Bo-sstones'
76 'Mighty-Mighty-Bo-sstones'
77 """
77 """
78
78
79 if str_.find(replace * 2) == -1:
79 if str_.find(replace * 2) == -1:
80 return str_
80 return str_
81 else:
81 else:
82 str_ = str_.replace(replace * 2, replace)
82 str_ = str_.replace(replace * 2, replace)
83 return recursive_replace(str_, replace)
83 return recursive_replace(str_, replace)
84
84
85
85
86 def repo_name_slug(value):
86 def repo_name_slug(value):
87 """
87 """
88 Return slug of name of repository
88 Return slug of name of repository
89 This function is called on each creation/modification
89 This function is called on each creation/modification
90 of repository to prevent bad names in repo
90 of repository to prevent bad names in repo
91 """
91 """
92
92
93 slug = remove_formatting(value)
93 slug = remove_formatting(value)
94 slug = strip_tags(slug)
94 slug = strip_tags(slug)
95
95
96 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
96 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
97 slug = slug.replace(c, '-')
97 slug = slug.replace(c, '-')
98 slug = recursive_replace(slug, '-')
98 slug = recursive_replace(slug, '-')
99 slug = collapse(slug, '-')
99 slug = collapse(slug, '-')
100 return slug
100 return slug
101
101
102
102
103 def get_repo_slug(request):
103 def get_repo_slug(request):
104 _repo = request.environ['pylons.routes_dict'].get('repo_name')
104 _repo = request.environ['pylons.routes_dict'].get('repo_name')
105 if _repo:
105 if _repo:
106 _repo = _repo.rstrip('/')
106 _repo = _repo.rstrip('/')
107 return _repo
107 return _repo
108
108
109
109
110 def get_repos_group_slug(request):
110 def get_repos_group_slug(request):
111 _group = request.environ['pylons.routes_dict'].get('group_name')
111 _group = request.environ['pylons.routes_dict'].get('group_name')
112 if _group:
112 if _group:
113 _group = _group.rstrip('/')
113 _group = _group.rstrip('/')
114 return _group
114 return _group
115
115
116
116
117 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
117 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
118 """
118 """
119 Action logger for various actions made by users
119 Action logger for various actions made by users
120
120
121 :param user: user that made this action, can be a unique username string or
121 :param user: user that made this action, can be a unique username string or
122 object containing user_id attribute
122 object containing user_id attribute
123 :param action: action to log, should be on of predefined unique actions for
123 :param action: action to log, should be on of predefined unique actions for
124 easy translations
124 easy translations
125 :param repo: string name of repository or object containing repo_id,
125 :param repo: string name of repository or object containing repo_id,
126 that action was made on
126 that action was made on
127 :param ipaddr: optional ip address from what the action was made
127 :param ipaddr: optional ip address from what the action was made
128 :param sa: optional sqlalchemy session
128 :param sa: optional sqlalchemy session
129
129
130 """
130 """
131
131
132 if not sa:
132 if not sa:
133 sa = meta.Session()
133 sa = meta.Session()
134
134
135 try:
135 try:
136 if hasattr(user, 'user_id'):
136 if hasattr(user, 'user_id'):
137 user_obj = user
137 user_obj = User.get(user.user_id)
138 elif isinstance(user, basestring):
138 elif isinstance(user, basestring):
139 user_obj = User.get_by_username(user)
139 user_obj = User.get_by_username(user)
140 else:
140 else:
141 raise Exception('You have to provide a user object or a username')
141 raise Exception('You have to provide a user object or a username')
142
142
143 if hasattr(repo, 'repo_id'):
143 if hasattr(repo, 'repo_id'):
144 repo_obj = Repository.get(repo.repo_id)
144 repo_obj = Repository.get(repo.repo_id)
145 repo_name = repo_obj.repo_name
145 repo_name = repo_obj.repo_name
146 elif isinstance(repo, basestring):
146 elif isinstance(repo, basestring):
147 repo_name = repo.lstrip('/')
147 repo_name = repo.lstrip('/')
148 repo_obj = Repository.get_by_repo_name(repo_name)
148 repo_obj = Repository.get_by_repo_name(repo_name)
149 else:
149 else:
150 repo_obj = None
150 repo_obj = None
151 repo_name = ''
151 repo_name = ''
152
152
153 user_log = UserLog()
153 user_log = UserLog()
154 user_log.user_id = user_obj.user_id
154 user_log.user_id = user_obj.user_id
155 user_log.username = user_obj.username
155 user_log.action = safe_unicode(action)
156 user_log.action = safe_unicode(action)
156
157
157 user_log.repository = repo_obj
158 user_log.repository = repo_obj
158 user_log.repository_name = repo_name
159 user_log.repository_name = repo_name
159
160
160 user_log.action_date = datetime.datetime.now()
161 user_log.action_date = datetime.datetime.now()
161 user_log.user_ip = ipaddr
162 user_log.user_ip = ipaddr
162 sa.add(user_log)
163 sa.add(user_log)
163
164
164 log.info(
165 log.info(
165 'Adding user %s, action %s on %s' % (user_obj, action,
166 'Adding user %s, action %s on %s' % (user_obj, action,
166 safe_unicode(repo))
167 safe_unicode(repo))
167 )
168 )
168 if commit:
169 if commit:
169 sa.commit()
170 sa.commit()
170 except:
171 except:
171 log.error(traceback.format_exc())
172 log.error(traceback.format_exc())
172 raise
173 raise
173
174
174
175
175 def get_repos(path, recursive=False):
176 def get_repos(path, recursive=False):
176 """
177 """
177 Scans given path for repos and return (name,(type,path)) tuple
178 Scans given path for repos and return (name,(type,path)) tuple
178
179
179 :param path: path to scan for repositories
180 :param path: path to scan for repositories
180 :param recursive: recursive search and return names with subdirs in front
181 :param recursive: recursive search and return names with subdirs in front
181 """
182 """
182
183
183 # remove ending slash for better results
184 # remove ending slash for better results
184 path = path.rstrip(os.sep)
185 path = path.rstrip(os.sep)
185
186
186 def _get_repos(p):
187 def _get_repos(p):
187 if not os.access(p, os.W_OK):
188 if not os.access(p, os.W_OK):
188 return
189 return
189 for dirpath in os.listdir(p):
190 for dirpath in os.listdir(p):
190 if os.path.isfile(os.path.join(p, dirpath)):
191 if os.path.isfile(os.path.join(p, dirpath)):
191 continue
192 continue
192 cur_path = os.path.join(p, dirpath)
193 cur_path = os.path.join(p, dirpath)
193 try:
194 try:
194 scm_info = get_scm(cur_path)
195 scm_info = get_scm(cur_path)
195 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
196 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
196 except VCSError:
197 except VCSError:
197 if not recursive:
198 if not recursive:
198 continue
199 continue
199 #check if this dir containts other repos for recursive scan
200 #check if this dir containts other repos for recursive scan
200 rec_path = os.path.join(p, dirpath)
201 rec_path = os.path.join(p, dirpath)
201 if os.path.isdir(rec_path):
202 if os.path.isdir(rec_path):
202 for inner_scm in _get_repos(rec_path):
203 for inner_scm in _get_repos(rec_path):
203 yield inner_scm
204 yield inner_scm
204
205
205 return _get_repos(path)
206 return _get_repos(path)
206
207
207
208
208 def is_valid_repo(repo_name, base_path, scm=None):
209 def is_valid_repo(repo_name, base_path, scm=None):
209 """
210 """
210 Returns True if given path is a valid repository False otherwise.
211 Returns True if given path is a valid repository False otherwise.
211 If scm param is given also compare if given scm is the same as expected
212 If scm param is given also compare if given scm is the same as expected
212 from scm parameter
213 from scm parameter
213
214
214 :param repo_name:
215 :param repo_name:
215 :param base_path:
216 :param base_path:
216 :param scm:
217 :param scm:
217
218
218 :return True: if given path is a valid repository
219 :return True: if given path is a valid repository
219 """
220 """
220 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
221 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
221
222
222 try:
223 try:
223 scm_ = get_scm(full_path)
224 scm_ = get_scm(full_path)
224 if scm:
225 if scm:
225 return scm_[0] == scm
226 return scm_[0] == scm
226 return True
227 return True
227 except VCSError:
228 except VCSError:
228 return False
229 return False
229
230
230
231
231 def is_valid_repos_group(repos_group_name, base_path):
232 def is_valid_repos_group(repos_group_name, base_path):
232 """
233 """
233 Returns True if given path is a repos group False otherwise
234 Returns True if given path is a repos group False otherwise
234
235
235 :param repo_name:
236 :param repo_name:
236 :param base_path:
237 :param base_path:
237 """
238 """
238 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
239 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
239
240
240 # check if it's not a repo
241 # check if it's not a repo
241 if is_valid_repo(repos_group_name, base_path):
242 if is_valid_repo(repos_group_name, base_path):
242 return False
243 return False
243
244
244 try:
245 try:
245 # we need to check bare git repos at higher level
246 # we need to check bare git repos at higher level
246 # since we might match branches/hooks/info/objects or possible
247 # since we might match branches/hooks/info/objects or possible
247 # other things inside bare git repo
248 # other things inside bare git repo
248 get_scm(os.path.dirname(full_path))
249 get_scm(os.path.dirname(full_path))
249 return False
250 return False
250 except VCSError:
251 except VCSError:
251 pass
252 pass
252
253
253 # check if it's a valid path
254 # check if it's a valid path
254 if os.path.isdir(full_path):
255 if os.path.isdir(full_path):
255 return True
256 return True
256
257
257 return False
258 return False
258
259
259
260
260 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
261 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
261 while True:
262 while True:
262 ok = raw_input(prompt)
263 ok = raw_input(prompt)
263 if ok in ('y', 'ye', 'yes'):
264 if ok in ('y', 'ye', 'yes'):
264 return True
265 return True
265 if ok in ('n', 'no', 'nop', 'nope'):
266 if ok in ('n', 'no', 'nop', 'nope'):
266 return False
267 return False
267 retries = retries - 1
268 retries = retries - 1
268 if retries < 0:
269 if retries < 0:
269 raise IOError
270 raise IOError
270 print complaint
271 print complaint
271
272
272 #propagated from mercurial documentation
273 #propagated from mercurial documentation
273 ui_sections = ['alias', 'auth',
274 ui_sections = ['alias', 'auth',
274 'decode/encode', 'defaults',
275 'decode/encode', 'defaults',
275 'diff', 'email',
276 'diff', 'email',
276 'extensions', 'format',
277 'extensions', 'format',
277 'merge-patterns', 'merge-tools',
278 'merge-patterns', 'merge-tools',
278 'hooks', 'http_proxy',
279 'hooks', 'http_proxy',
279 'smtp', 'patch',
280 'smtp', 'patch',
280 'paths', 'profiling',
281 'paths', 'profiling',
281 'server', 'trusted',
282 'server', 'trusted',
282 'ui', 'web', ]
283 'ui', 'web', ]
283
284
284
285
285 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
286 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
286 """
287 """
287 A function that will read python rc files or database
288 A function that will read python rc files or database
288 and make an mercurial ui object from read options
289 and make an mercurial ui object from read options
289
290
290 :param path: path to mercurial config file
291 :param path: path to mercurial config file
291 :param checkpaths: check the path
292 :param checkpaths: check the path
292 :param read_from: read from 'file' or 'db'
293 :param read_from: read from 'file' or 'db'
293 """
294 """
294
295
295 baseui = ui.ui()
296 baseui = ui.ui()
296
297
297 # clean the baseui object
298 # clean the baseui object
298 baseui._ocfg = config.config()
299 baseui._ocfg = config.config()
299 baseui._ucfg = config.config()
300 baseui._ucfg = config.config()
300 baseui._tcfg = config.config()
301 baseui._tcfg = config.config()
301
302
302 if read_from == 'file':
303 if read_from == 'file':
303 if not os.path.isfile(path):
304 if not os.path.isfile(path):
304 log.debug('hgrc file is not present at %s, skipping...' % path)
305 log.debug('hgrc file is not present at %s, skipping...' % path)
305 return False
306 return False
306 log.debug('reading hgrc from %s' % path)
307 log.debug('reading hgrc from %s' % path)
307 cfg = config.config()
308 cfg = config.config()
308 cfg.read(path)
309 cfg.read(path)
309 for section in ui_sections:
310 for section in ui_sections:
310 for k, v in cfg.items(section):
311 for k, v in cfg.items(section):
311 log.debug('settings ui from file[%s]%s:%s' % (section, k, v))
312 log.debug('settings ui from file[%s]%s:%s' % (section, k, v))
312 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
313 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
313
314
314 elif read_from == 'db':
315 elif read_from == 'db':
315 sa = meta.Session()
316 sa = meta.Session()
316 ret = sa.query(RhodeCodeUi)\
317 ret = sa.query(RhodeCodeUi)\
317 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
318 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
318 .all()
319 .all()
319
320
320 hg_ui = ret
321 hg_ui = ret
321 for ui_ in hg_ui:
322 for ui_ in hg_ui:
322 if ui_.ui_active:
323 if ui_.ui_active:
323 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
324 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
324 ui_.ui_key, ui_.ui_value)
325 ui_.ui_key, ui_.ui_value)
325 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
326 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
326 safe_str(ui_.ui_value))
327 safe_str(ui_.ui_value))
327 if ui_.ui_key == 'push_ssl':
328 if ui_.ui_key == 'push_ssl':
328 # force set push_ssl requirement to False, rhodecode
329 # force set push_ssl requirement to False, rhodecode
329 # handles that
330 # handles that
330 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
331 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
331 False)
332 False)
332 if clear_session:
333 if clear_session:
333 meta.Session.remove()
334 meta.Session.remove()
334 return baseui
335 return baseui
335
336
336
337
337 def set_rhodecode_config(config):
338 def set_rhodecode_config(config):
338 """
339 """
339 Updates pylons config with new settings from database
340 Updates pylons config with new settings from database
340
341
341 :param config:
342 :param config:
342 """
343 """
343 hgsettings = RhodeCodeSetting.get_app_settings()
344 hgsettings = RhodeCodeSetting.get_app_settings()
344
345
345 for k, v in hgsettings.items():
346 for k, v in hgsettings.items():
346 config[k] = v
347 config[k] = v
347
348
348
349
349 def invalidate_cache(cache_key, *args):
350 def invalidate_cache(cache_key, *args):
350 """
351 """
351 Puts cache invalidation task into db for
352 Puts cache invalidation task into db for
352 further global cache invalidation
353 further global cache invalidation
353 """
354 """
354
355
355 from rhodecode.model.scm import ScmModel
356 from rhodecode.model.scm import ScmModel
356
357
357 if cache_key.startswith('get_repo_cached_'):
358 if cache_key.startswith('get_repo_cached_'):
358 name = cache_key.split('get_repo_cached_')[-1]
359 name = cache_key.split('get_repo_cached_')[-1]
359 ScmModel().mark_for_invalidation(name)
360 ScmModel().mark_for_invalidation(name)
360
361
361
362
362 def map_groups(path):
363 def map_groups(path):
363 """
364 """
364 Given a full path to a repository, create all nested groups that this
365 Given a full path to a repository, create all nested groups that this
365 repo is inside. This function creates parent-child relationships between
366 repo is inside. This function creates parent-child relationships between
366 groups and creates default perms for all new groups.
367 groups and creates default perms for all new groups.
367
368
368 :param paths: full path to repository
369 :param paths: full path to repository
369 """
370 """
370 sa = meta.Session()
371 sa = meta.Session()
371 groups = path.split(Repository.url_sep())
372 groups = path.split(Repository.url_sep())
372 parent = None
373 parent = None
373 group = None
374 group = None
374
375
375 # last element is repo in nested groups structure
376 # last element is repo in nested groups structure
376 groups = groups[:-1]
377 groups = groups[:-1]
377 rgm = ReposGroupModel(sa)
378 rgm = ReposGroupModel(sa)
378 for lvl, group_name in enumerate(groups):
379 for lvl, group_name in enumerate(groups):
379 group_name = '/'.join(groups[:lvl] + [group_name])
380 group_name = '/'.join(groups[:lvl] + [group_name])
380 group = RepoGroup.get_by_group_name(group_name)
381 group = RepoGroup.get_by_group_name(group_name)
381 desc = '%s group' % group_name
382 desc = '%s group' % group_name
382
383
383 # skip folders that are now removed repos
384 # skip folders that are now removed repos
384 if REMOVED_REPO_PAT.match(group_name):
385 if REMOVED_REPO_PAT.match(group_name):
385 break
386 break
386
387
387 if group is None:
388 if group is None:
388 log.debug('creating group level: %s group_name: %s' % (lvl,
389 log.debug('creating group level: %s group_name: %s' % (lvl,
389 group_name))
390 group_name))
390 group = RepoGroup(group_name, parent)
391 group = RepoGroup(group_name, parent)
391 group.group_description = desc
392 group.group_description = desc
392 sa.add(group)
393 sa.add(group)
393 rgm._create_default_perms(group)
394 rgm._create_default_perms(group)
394 sa.flush()
395 sa.flush()
395 parent = group
396 parent = group
396 return group
397 return group
397
398
398
399
399 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
400 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
400 install_git_hook=False):
401 install_git_hook=False):
401 """
402 """
402 maps all repos given in initial_repo_list, non existing repositories
403 maps all repos given in initial_repo_list, non existing repositories
403 are created, if remove_obsolete is True it also check for db entries
404 are created, if remove_obsolete is True it also check for db entries
404 that are not in initial_repo_list and removes them.
405 that are not in initial_repo_list and removes them.
405
406
406 :param initial_repo_list: list of repositories found by scanning methods
407 :param initial_repo_list: list of repositories found by scanning methods
407 :param remove_obsolete: check for obsolete entries in database
408 :param remove_obsolete: check for obsolete entries in database
408 :param install_git_hook: if this is True, also check and install githook
409 :param install_git_hook: if this is True, also check and install githook
409 for a repo if missing
410 for a repo if missing
410 """
411 """
411 from rhodecode.model.repo import RepoModel
412 from rhodecode.model.repo import RepoModel
412 from rhodecode.model.scm import ScmModel
413 from rhodecode.model.scm import ScmModel
413 sa = meta.Session()
414 sa = meta.Session()
414 rm = RepoModel()
415 rm = RepoModel()
415 user = sa.query(User).filter(User.admin == True).first()
416 user = sa.query(User).filter(User.admin == True).first()
416 if user is None:
417 if user is None:
417 raise Exception('Missing administrative account!')
418 raise Exception('Missing administrative account!')
418 added = []
419 added = []
419
420
420 # # clear cache keys
421 # # clear cache keys
421 # log.debug("Clearing cache keys now...")
422 # log.debug("Clearing cache keys now...")
422 # CacheInvalidation.clear_cache()
423 # CacheInvalidation.clear_cache()
423 # sa.commit()
424 # sa.commit()
424
425
425 for name, repo in initial_repo_list.items():
426 for name, repo in initial_repo_list.items():
426 group = map_groups(name)
427 group = map_groups(name)
427 db_repo = rm.get_by_repo_name(name)
428 db_repo = rm.get_by_repo_name(name)
428 # found repo that is on filesystem not in RhodeCode database
429 # found repo that is on filesystem not in RhodeCode database
429 if not db_repo:
430 if not db_repo:
430 log.info('repository %s not found, creating now' % name)
431 log.info('repository %s not found, creating now' % name)
431 added.append(name)
432 added.append(name)
432 desc = (repo.description
433 desc = (repo.description
433 if repo.description != 'unknown'
434 if repo.description != 'unknown'
434 else '%s repository' % name)
435 else '%s repository' % name)
435 new_repo = rm.create_repo(
436 new_repo = rm.create_repo(
436 repo_name=name,
437 repo_name=name,
437 repo_type=repo.alias,
438 repo_type=repo.alias,
438 description=desc,
439 description=desc,
439 repos_group=getattr(group, 'group_id', None),
440 repos_group=getattr(group, 'group_id', None),
440 owner=user,
441 owner=user,
441 just_db=True
442 just_db=True
442 )
443 )
443 # we added that repo just now, and make sure it has githook
444 # we added that repo just now, and make sure it has githook
444 # installed
445 # installed
445 if new_repo.repo_type == 'git':
446 if new_repo.repo_type == 'git':
446 ScmModel().install_git_hook(new_repo.scm_instance)
447 ScmModel().install_git_hook(new_repo.scm_instance)
447 elif install_git_hook:
448 elif install_git_hook:
448 if db_repo.repo_type == 'git':
449 if db_repo.repo_type == 'git':
449 ScmModel().install_git_hook(db_repo.scm_instance)
450 ScmModel().install_git_hook(db_repo.scm_instance)
450 # during starting install all cache keys for all repositories in the
451 # during starting install all cache keys for all repositories in the
451 # system, this will register all repos and multiple instances
452 # system, this will register all repos and multiple instances
452 key, _prefix, _org_key = CacheInvalidation._get_key(name)
453 key, _prefix, _org_key = CacheInvalidation._get_key(name)
453 CacheInvalidation.invalidate(name)
454 CacheInvalidation.invalidate(name)
454 log.debug("Creating a cache key for %s instance_id=>`%s`"
455 log.debug("Creating a cache key for %s instance_id=>`%s`"
455 % (name, _prefix or '-'))
456 % (name, _prefix or '-'))
456
457
457 sa.commit()
458 sa.commit()
458 removed = []
459 removed = []
459 if remove_obsolete:
460 if remove_obsolete:
460 # remove from database those repositories that are not in the filesystem
461 # remove from database those repositories that are not in the filesystem
461 for repo in sa.query(Repository).all():
462 for repo in sa.query(Repository).all():
462 if repo.repo_name not in initial_repo_list.keys():
463 if repo.repo_name not in initial_repo_list.keys():
463 log.debug("Removing non-existing repository found in db `%s`" %
464 log.debug("Removing non-existing repository found in db `%s`" %
464 repo.repo_name)
465 repo.repo_name)
465 try:
466 try:
466 sa.delete(repo)
467 sa.delete(repo)
467 sa.commit()
468 sa.commit()
468 removed.append(repo.repo_name)
469 removed.append(repo.repo_name)
469 except:
470 except:
470 #don't hold further removals on error
471 #don't hold further removals on error
471 log.error(traceback.format_exc())
472 log.error(traceback.format_exc())
472 sa.rollback()
473 sa.rollback()
473
474
474 return added, removed
475 return added, removed
475
476
476
477
477 # set cache regions for beaker so celery can utilise it
478 # set cache regions for beaker so celery can utilise it
478 def add_cache(settings):
479 def add_cache(settings):
479 cache_settings = {'regions': None}
480 cache_settings = {'regions': None}
480 for key in settings.keys():
481 for key in settings.keys():
481 for prefix in ['beaker.cache.', 'cache.']:
482 for prefix in ['beaker.cache.', 'cache.']:
482 if key.startswith(prefix):
483 if key.startswith(prefix):
483 name = key.split(prefix)[1].strip()
484 name = key.split(prefix)[1].strip()
484 cache_settings[name] = settings[key].strip()
485 cache_settings[name] = settings[key].strip()
485 if cache_settings['regions']:
486 if cache_settings['regions']:
486 for region in cache_settings['regions'].split(','):
487 for region in cache_settings['regions'].split(','):
487 region = region.strip()
488 region = region.strip()
488 region_settings = {}
489 region_settings = {}
489 for key, value in cache_settings.items():
490 for key, value in cache_settings.items():
490 if key.startswith(region):
491 if key.startswith(region):
491 region_settings[key.split('.')[1]] = value
492 region_settings[key.split('.')[1]] = value
492 region_settings['expire'] = int(region_settings.get('expire',
493 region_settings['expire'] = int(region_settings.get('expire',
493 60))
494 60))
494 region_settings.setdefault('lock_dir',
495 region_settings.setdefault('lock_dir',
495 cache_settings.get('lock_dir'))
496 cache_settings.get('lock_dir'))
496 region_settings.setdefault('data_dir',
497 region_settings.setdefault('data_dir',
497 cache_settings.get('data_dir'))
498 cache_settings.get('data_dir'))
498
499
499 if 'type' not in region_settings:
500 if 'type' not in region_settings:
500 region_settings['type'] = cache_settings.get('type',
501 region_settings['type'] = cache_settings.get('type',
501 'memory')
502 'memory')
502 beaker.cache.cache_regions[region] = region_settings
503 beaker.cache.cache_regions[region] = region_settings
503
504
504
505
505 def load_rcextensions(root_path):
506 def load_rcextensions(root_path):
506 import rhodecode
507 import rhodecode
507 from rhodecode.config import conf
508 from rhodecode.config import conf
508
509
509 path = os.path.join(root_path, 'rcextensions', '__init__.py')
510 path = os.path.join(root_path, 'rcextensions', '__init__.py')
510 if os.path.isfile(path):
511 if os.path.isfile(path):
511 rcext = create_module('rc', path)
512 rcext = create_module('rc', path)
512 EXT = rhodecode.EXTENSIONS = rcext
513 EXT = rhodecode.EXTENSIONS = rcext
513 log.debug('Found rcextensions now loading %s...' % rcext)
514 log.debug('Found rcextensions now loading %s...' % rcext)
514
515
515 # Additional mappings that are not present in the pygments lexers
516 # Additional mappings that are not present in the pygments lexers
516 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
517 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
517
518
518 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
519 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
519
520
520 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
521 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
521 log.debug('settings custom INDEX_EXTENSIONS')
522 log.debug('settings custom INDEX_EXTENSIONS')
522 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
523 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
523
524
524 #ADDITIONAL MAPPINGS
525 #ADDITIONAL MAPPINGS
525 log.debug('adding extra into INDEX_EXTENSIONS')
526 log.debug('adding extra into INDEX_EXTENSIONS')
526 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
527 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
527
528
528
529
529 #==============================================================================
530 #==============================================================================
530 # TEST FUNCTIONS AND CREATORS
531 # TEST FUNCTIONS AND CREATORS
531 #==============================================================================
532 #==============================================================================
532 def create_test_index(repo_location, config, full_index):
533 def create_test_index(repo_location, config, full_index):
533 """
534 """
534 Makes default test index
535 Makes default test index
535
536
536 :param config: test config
537 :param config: test config
537 :param full_index:
538 :param full_index:
538 """
539 """
539
540
540 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
541 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
541 from rhodecode.lib.pidlock import DaemonLock, LockHeld
542 from rhodecode.lib.pidlock import DaemonLock, LockHeld
542
543
543 repo_location = repo_location
544 repo_location = repo_location
544
545
545 index_location = os.path.join(config['app_conf']['index_dir'])
546 index_location = os.path.join(config['app_conf']['index_dir'])
546 if not os.path.exists(index_location):
547 if not os.path.exists(index_location):
547 os.makedirs(index_location)
548 os.makedirs(index_location)
548
549
549 try:
550 try:
550 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
551 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
551 WhooshIndexingDaemon(index_location=index_location,
552 WhooshIndexingDaemon(index_location=index_location,
552 repo_location=repo_location)\
553 repo_location=repo_location)\
553 .run(full_index=full_index)
554 .run(full_index=full_index)
554 l.release()
555 l.release()
555 except LockHeld:
556 except LockHeld:
556 pass
557 pass
557
558
558
559
559 def create_test_env(repos_test_path, config):
560 def create_test_env(repos_test_path, config):
560 """
561 """
561 Makes a fresh database and
562 Makes a fresh database and
562 install test repository into tmp dir
563 install test repository into tmp dir
563 """
564 """
564 from rhodecode.lib.db_manage import DbManage
565 from rhodecode.lib.db_manage import DbManage
565 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
566 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
566
567
567 # PART ONE create db
568 # PART ONE create db
568 dbconf = config['sqlalchemy.db1.url']
569 dbconf = config['sqlalchemy.db1.url']
569 log.debug('making test db %s' % dbconf)
570 log.debug('making test db %s' % dbconf)
570
571
571 # create test dir if it doesn't exist
572 # create test dir if it doesn't exist
572 if not os.path.isdir(repos_test_path):
573 if not os.path.isdir(repos_test_path):
573 log.debug('Creating testdir %s' % repos_test_path)
574 log.debug('Creating testdir %s' % repos_test_path)
574 os.makedirs(repos_test_path)
575 os.makedirs(repos_test_path)
575
576
576 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
577 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
577 tests=True)
578 tests=True)
578 dbmanage.create_tables(override=True)
579 dbmanage.create_tables(override=True)
579 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
580 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
580 dbmanage.create_default_user()
581 dbmanage.create_default_user()
581 dbmanage.admin_prompt()
582 dbmanage.admin_prompt()
582 dbmanage.create_permissions()
583 dbmanage.create_permissions()
583 dbmanage.populate_default_permissions()
584 dbmanage.populate_default_permissions()
584 Session().commit()
585 Session().commit()
585 # PART TWO make test repo
586 # PART TWO make test repo
586 log.debug('making test vcs repositories')
587 log.debug('making test vcs repositories')
587
588
588 idx_path = config['app_conf']['index_dir']
589 idx_path = config['app_conf']['index_dir']
589 data_path = config['app_conf']['cache_dir']
590 data_path = config['app_conf']['cache_dir']
590
591
591 #clean index and data
592 #clean index and data
592 if idx_path and os.path.exists(idx_path):
593 if idx_path and os.path.exists(idx_path):
593 log.debug('remove %s' % idx_path)
594 log.debug('remove %s' % idx_path)
594 shutil.rmtree(idx_path)
595 shutil.rmtree(idx_path)
595
596
596 if data_path and os.path.exists(data_path):
597 if data_path and os.path.exists(data_path):
597 log.debug('remove %s' % data_path)
598 log.debug('remove %s' % data_path)
598 shutil.rmtree(data_path)
599 shutil.rmtree(data_path)
599
600
600 #CREATE DEFAULT TEST REPOS
601 #CREATE DEFAULT TEST REPOS
601 cur_dir = dn(dn(abspath(__file__)))
602 cur_dir = dn(dn(abspath(__file__)))
602 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
603 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
603 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
604 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
604 tar.close()
605 tar.close()
605
606
606 cur_dir = dn(dn(abspath(__file__)))
607 cur_dir = dn(dn(abspath(__file__)))
607 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
608 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
608 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
609 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
609 tar.close()
610 tar.close()
610
611
611 #LOAD VCS test stuff
612 #LOAD VCS test stuff
612 from rhodecode.tests.vcs import setup_package
613 from rhodecode.tests.vcs import setup_package
613 setup_package()
614 setup_package()
614
615
615
616
616 #==============================================================================
617 #==============================================================================
617 # PASTER COMMANDS
618 # PASTER COMMANDS
618 #==============================================================================
619 #==============================================================================
619 class BasePasterCommand(Command):
620 class BasePasterCommand(Command):
620 """
621 """
621 Abstract Base Class for paster commands.
622 Abstract Base Class for paster commands.
622
623
623 The celery commands are somewhat aggressive about loading
624 The celery commands are somewhat aggressive about loading
624 celery.conf, and since our module sets the `CELERY_LOADER`
625 celery.conf, and since our module sets the `CELERY_LOADER`
625 environment variable to our loader, we have to bootstrap a bit and
626 environment variable to our loader, we have to bootstrap a bit and
626 make sure we've had a chance to load the pylons config off of the
627 make sure we've had a chance to load the pylons config off of the
627 command line, otherwise everything fails.
628 command line, otherwise everything fails.
628 """
629 """
629 min_args = 1
630 min_args = 1
630 min_args_error = "Please provide a paster config file as an argument."
631 min_args_error = "Please provide a paster config file as an argument."
631 takes_config_file = 1
632 takes_config_file = 1
632 requires_config_file = True
633 requires_config_file = True
633
634
634 def notify_msg(self, msg, log=False):
635 def notify_msg(self, msg, log=False):
635 """Make a notification to user, additionally if logger is passed
636 """Make a notification to user, additionally if logger is passed
636 it logs this action using given logger
637 it logs this action using given logger
637
638
638 :param msg: message that will be printed to user
639 :param msg: message that will be printed to user
639 :param log: logging instance, to use to additionally log this message
640 :param log: logging instance, to use to additionally log this message
640
641
641 """
642 """
642 if log and isinstance(log, logging):
643 if log and isinstance(log, logging):
643 log(msg)
644 log(msg)
644
645
645 def run(self, args):
646 def run(self, args):
646 """
647 """
647 Overrides Command.run
648 Overrides Command.run
648
649
649 Checks for a config file argument and loads it.
650 Checks for a config file argument and loads it.
650 """
651 """
651 if len(args) < self.min_args:
652 if len(args) < self.min_args:
652 raise BadCommand(
653 raise BadCommand(
653 self.min_args_error % {'min_args': self.min_args,
654 self.min_args_error % {'min_args': self.min_args,
654 'actual_args': len(args)})
655 'actual_args': len(args)})
655
656
656 # Decrement because we're going to lob off the first argument.
657 # Decrement because we're going to lob off the first argument.
657 # @@ This is hacky
658 # @@ This is hacky
658 self.min_args -= 1
659 self.min_args -= 1
659 self.bootstrap_config(args[0])
660 self.bootstrap_config(args[0])
660 self.update_parser()
661 self.update_parser()
661 return super(BasePasterCommand, self).run(args[1:])
662 return super(BasePasterCommand, self).run(args[1:])
662
663
663 def update_parser(self):
664 def update_parser(self):
664 """
665 """
665 Abstract method. Allows for the class's parser to be updated
666 Abstract method. Allows for the class's parser to be updated
666 before the superclass's `run` method is called. Necessary to
667 before the superclass's `run` method is called. Necessary to
667 allow options/arguments to be passed through to the underlying
668 allow options/arguments to be passed through to the underlying
668 celery command.
669 celery command.
669 """
670 """
670 raise NotImplementedError("Abstract Method.")
671 raise NotImplementedError("Abstract Method.")
671
672
672 def bootstrap_config(self, conf):
673 def bootstrap_config(self, conf):
673 """
674 """
674 Loads the pylons configuration.
675 Loads the pylons configuration.
675 """
676 """
676 from pylons import config as pylonsconfig
677 from pylons import config as pylonsconfig
677
678
678 self.path_to_ini_file = os.path.realpath(conf)
679 self.path_to_ini_file = os.path.realpath(conf)
679 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
680 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
680 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
681 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
681
682
682
683
683 def check_git_version():
684 def check_git_version():
684 """
685 """
685 Checks what version of git is installed in system, and issues a warning
686 Checks what version of git is installed in system, and issues a warning
686 if it's too old for RhodeCode to properly work.
687 if it's too old for RhodeCode to properly work.
687 """
688 """
688 import subprocess
689 import subprocess
689 from distutils.version import StrictVersion
690 from distutils.version import StrictVersion
690 from rhodecode import BACKENDS
691 from rhodecode import BACKENDS
691
692
692 p = subprocess.Popen('git --version', shell=True,
693 p = subprocess.Popen('git --version', shell=True,
693 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
694 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
694 stdout, stderr = p.communicate()
695 stdout, stderr = p.communicate()
695 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
696 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
696 if len(ver.split('.')) > 3:
697 if len(ver.split('.')) > 3:
697 #StrictVersion needs to be only 3 element type
698 #StrictVersion needs to be only 3 element type
698 ver = '.'.join(ver.split('.')[:3])
699 ver = '.'.join(ver.split('.')[:3])
699 try:
700 try:
700 _ver = StrictVersion(ver)
701 _ver = StrictVersion(ver)
701 except:
702 except:
702 _ver = StrictVersion('0.0.0')
703 _ver = StrictVersion('0.0.0')
703 stderr = traceback.format_exc()
704 stderr = traceback.format_exc()
704
705
705 req_ver = '1.7.4'
706 req_ver = '1.7.4'
706 to_old_git = False
707 to_old_git = False
707 if _ver < StrictVersion(req_ver):
708 if _ver < StrictVersion(req_ver):
708 to_old_git = True
709 to_old_git = True
709
710
710 if 'git' in BACKENDS:
711 if 'git' in BACKENDS:
711 log.debug('GIT version detected: %s' % stdout)
712 log.debug('GIT version detected: %s' % stdout)
712 if stderr:
713 if stderr:
713 log.warning('Unable to detect git version org error was:%r' % stderr)
714 log.warning('Unable to detect git version org error was:%r' % stderr)
714 elif to_old_git:
715 elif to_old_git:
715 log.warning('RhodeCode detected git version %s, which is too old '
716 log.warning('RhodeCode detected git version %s, which is too old '
716 'for the system to function properly. Make sure '
717 'for the system to function properly. Make sure '
717 'its version is at least %s' % (ver, req_ver))
718 'its version is at least %s' % (ver, req_ver))
718 return _ver
719 return _ver
719
720
720
721
721 @decorator.decorator
722 @decorator.decorator
722 def jsonify(func, *args, **kwargs):
723 def jsonify(func, *args, **kwargs):
723 """Action decorator that formats output for JSON
724 """Action decorator that formats output for JSON
724
725
725 Given a function that will return content, this decorator will turn
726 Given a function that will return content, this decorator will turn
726 the result into JSON, with a content-type of 'application/json' and
727 the result into JSON, with a content-type of 'application/json' and
727 output it.
728 output it.
728
729
729 """
730 """
730 from pylons.decorators.util import get_pylons
731 from pylons.decorators.util import get_pylons
731 from rhodecode.lib.ext_json import json
732 from rhodecode.lib.ext_json import json
732 pylons = get_pylons(args)
733 pylons = get_pylons(args)
733 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
734 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
734 data = func(*args, **kwargs)
735 data = func(*args, **kwargs)
735 if isinstance(data, (list, tuple)):
736 if isinstance(data, (list, tuple)):
736 msg = "JSON responses with Array envelopes are susceptible to " \
737 msg = "JSON responses with Array envelopes are susceptible to " \
737 "cross-site data leak attacks, see " \
738 "cross-site data leak attacks, see " \
738 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
739 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
739 warnings.warn(msg, Warning, 2)
740 warnings.warn(msg, Warning, 2)
740 log.warning(msg)
741 log.warning(msg)
741 log.debug("Returning JSON wrapped action output")
742 log.debug("Returning JSON wrapped action output")
742 return json.dumps(data, encoding='utf-8') No newline at end of file
743 return json.dumps(data, encoding='utf-8')
@@ -1,1831 +1,1831 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.db
3 rhodecode.model.db
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 Database Models for RhodeCode
6 Database Models for RhodeCode
7
7
8 :created_on: Apr 08, 2010
8 :created_on: Apr 08, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import datetime
28 import datetime
29 import traceback
29 import traceback
30 import hashlib
30 import hashlib
31 import time
31 import time
32 from collections import defaultdict
32 from collections import defaultdict
33
33
34 from sqlalchemy import *
34 from sqlalchemy import *
35 from sqlalchemy.ext.hybrid import hybrid_property
35 from sqlalchemy.ext.hybrid import hybrid_property
36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
37 from sqlalchemy.exc import DatabaseError
37 from sqlalchemy.exc import DatabaseError
38 from beaker.cache import cache_region, region_invalidate
38 from beaker.cache import cache_region, region_invalidate
39 from webob.exc import HTTPNotFound
39 from webob.exc import HTTPNotFound
40
40
41 from pylons.i18n.translation import lazy_ugettext as _
41 from pylons.i18n.translation import lazy_ugettext as _
42
42
43 from rhodecode.lib.vcs import get_backend
43 from rhodecode.lib.vcs import get_backend
44 from rhodecode.lib.vcs.utils.helpers import get_scm
44 from rhodecode.lib.vcs.utils.helpers import get_scm
45 from rhodecode.lib.vcs.exceptions import VCSError
45 from rhodecode.lib.vcs.exceptions import VCSError
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47
47
48 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
48 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
49 safe_unicode, remove_suffix, remove_prefix
49 safe_unicode, remove_suffix, remove_prefix
50 from rhodecode.lib.compat import json
50 from rhodecode.lib.compat import json
51 from rhodecode.lib.caching_query import FromCache
51 from rhodecode.lib.caching_query import FromCache
52
52
53 from rhodecode.model.meta import Base, Session
53 from rhodecode.model.meta import Base, Session
54
54
55 URL_SEP = '/'
55 URL_SEP = '/'
56 log = logging.getLogger(__name__)
56 log = logging.getLogger(__name__)
57
57
58 #==============================================================================
58 #==============================================================================
59 # BASE CLASSES
59 # BASE CLASSES
60 #==============================================================================
60 #==============================================================================
61
61
62 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
62 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
63
63
64
64
65 class BaseModel(object):
65 class BaseModel(object):
66 """
66 """
67 Base Model for all classess
67 Base Model for all classess
68 """
68 """
69
69
70 @classmethod
70 @classmethod
71 def _get_keys(cls):
71 def _get_keys(cls):
72 """return column names for this model """
72 """return column names for this model """
73 return class_mapper(cls).c.keys()
73 return class_mapper(cls).c.keys()
74
74
75 def get_dict(self):
75 def get_dict(self):
76 """
76 """
77 return dict with keys and values corresponding
77 return dict with keys and values corresponding
78 to this model data """
78 to this model data """
79
79
80 d = {}
80 d = {}
81 for k in self._get_keys():
81 for k in self._get_keys():
82 d[k] = getattr(self, k)
82 d[k] = getattr(self, k)
83
83
84 # also use __json__() if present to get additional fields
84 # also use __json__() if present to get additional fields
85 _json_attr = getattr(self, '__json__', None)
85 _json_attr = getattr(self, '__json__', None)
86 if _json_attr:
86 if _json_attr:
87 # update with attributes from __json__
87 # update with attributes from __json__
88 if callable(_json_attr):
88 if callable(_json_attr):
89 _json_attr = _json_attr()
89 _json_attr = _json_attr()
90 for k, val in _json_attr.iteritems():
90 for k, val in _json_attr.iteritems():
91 d[k] = val
91 d[k] = val
92 return d
92 return d
93
93
94 def get_appstruct(self):
94 def get_appstruct(self):
95 """return list with keys and values tupples corresponding
95 """return list with keys and values tupples corresponding
96 to this model data """
96 to this model data """
97
97
98 l = []
98 l = []
99 for k in self._get_keys():
99 for k in self._get_keys():
100 l.append((k, getattr(self, k),))
100 l.append((k, getattr(self, k),))
101 return l
101 return l
102
102
103 def populate_obj(self, populate_dict):
103 def populate_obj(self, populate_dict):
104 """populate model with data from given populate_dict"""
104 """populate model with data from given populate_dict"""
105
105
106 for k in self._get_keys():
106 for k in self._get_keys():
107 if k in populate_dict:
107 if k in populate_dict:
108 setattr(self, k, populate_dict[k])
108 setattr(self, k, populate_dict[k])
109
109
110 @classmethod
110 @classmethod
111 def query(cls):
111 def query(cls):
112 return Session().query(cls)
112 return Session().query(cls)
113
113
114 @classmethod
114 @classmethod
115 def get(cls, id_):
115 def get(cls, id_):
116 if id_:
116 if id_:
117 return cls.query().get(id_)
117 return cls.query().get(id_)
118
118
119 @classmethod
119 @classmethod
120 def get_or_404(cls, id_):
120 def get_or_404(cls, id_):
121 try:
121 try:
122 id_ = int(id_)
122 id_ = int(id_)
123 except (TypeError, ValueError):
123 except (TypeError, ValueError):
124 raise HTTPNotFound
124 raise HTTPNotFound
125
125
126 res = cls.query().get(id_)
126 res = cls.query().get(id_)
127 if not res:
127 if not res:
128 raise HTTPNotFound
128 raise HTTPNotFound
129 return res
129 return res
130
130
131 @classmethod
131 @classmethod
132 def getAll(cls):
132 def getAll(cls):
133 return cls.query().all()
133 return cls.query().all()
134
134
135 @classmethod
135 @classmethod
136 def delete(cls, id_):
136 def delete(cls, id_):
137 obj = cls.query().get(id_)
137 obj = cls.query().get(id_)
138 Session().delete(obj)
138 Session().delete(obj)
139
139
140 def __repr__(self):
140 def __repr__(self):
141 if hasattr(self, '__unicode__'):
141 if hasattr(self, '__unicode__'):
142 # python repr needs to return str
142 # python repr needs to return str
143 return safe_str(self.__unicode__())
143 return safe_str(self.__unicode__())
144 return '<DB:%s>' % (self.__class__.__name__)
144 return '<DB:%s>' % (self.__class__.__name__)
145
145
146
146
147 class RhodeCodeSetting(Base, BaseModel):
147 class RhodeCodeSetting(Base, BaseModel):
148 __tablename__ = 'rhodecode_settings'
148 __tablename__ = 'rhodecode_settings'
149 __table_args__ = (
149 __table_args__ = (
150 UniqueConstraint('app_settings_name'),
150 UniqueConstraint('app_settings_name'),
151 {'extend_existing': True, 'mysql_engine': 'InnoDB',
151 {'extend_existing': True, 'mysql_engine': 'InnoDB',
152 'mysql_charset': 'utf8'}
152 'mysql_charset': 'utf8'}
153 )
153 )
154 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
154 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
155 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
155 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
156 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
156 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
157
157
158 def __init__(self, k='', v=''):
158 def __init__(self, k='', v=''):
159 self.app_settings_name = k
159 self.app_settings_name = k
160 self.app_settings_value = v
160 self.app_settings_value = v
161
161
162 @validates('_app_settings_value')
162 @validates('_app_settings_value')
163 def validate_settings_value(self, key, val):
163 def validate_settings_value(self, key, val):
164 assert type(val) == unicode
164 assert type(val) == unicode
165 return val
165 return val
166
166
167 @hybrid_property
167 @hybrid_property
168 def app_settings_value(self):
168 def app_settings_value(self):
169 v = self._app_settings_value
169 v = self._app_settings_value
170 if self.app_settings_name in ["ldap_active",
170 if self.app_settings_name in ["ldap_active",
171 "default_repo_enable_statistics",
171 "default_repo_enable_statistics",
172 "default_repo_enable_locking",
172 "default_repo_enable_locking",
173 "default_repo_private",
173 "default_repo_private",
174 "default_repo_enable_downloads"]:
174 "default_repo_enable_downloads"]:
175 v = str2bool(v)
175 v = str2bool(v)
176 return v
176 return v
177
177
178 @app_settings_value.setter
178 @app_settings_value.setter
179 def app_settings_value(self, val):
179 def app_settings_value(self, val):
180 """
180 """
181 Setter that will always make sure we use unicode in app_settings_value
181 Setter that will always make sure we use unicode in app_settings_value
182
182
183 :param val:
183 :param val:
184 """
184 """
185 self._app_settings_value = safe_unicode(val)
185 self._app_settings_value = safe_unicode(val)
186
186
187 def __unicode__(self):
187 def __unicode__(self):
188 return u"<%s('%s:%s')>" % (
188 return u"<%s('%s:%s')>" % (
189 self.__class__.__name__,
189 self.__class__.__name__,
190 self.app_settings_name, self.app_settings_value
190 self.app_settings_name, self.app_settings_value
191 )
191 )
192
192
193 @classmethod
193 @classmethod
194 def get_by_name(cls, key):
194 def get_by_name(cls, key):
195 return cls.query()\
195 return cls.query()\
196 .filter(cls.app_settings_name == key).scalar()
196 .filter(cls.app_settings_name == key).scalar()
197
197
198 @classmethod
198 @classmethod
199 def get_by_name_or_create(cls, key):
199 def get_by_name_or_create(cls, key):
200 res = cls.get_by_name(key)
200 res = cls.get_by_name(key)
201 if not res:
201 if not res:
202 res = cls(key)
202 res = cls(key)
203 return res
203 return res
204
204
205 @classmethod
205 @classmethod
206 def get_app_settings(cls, cache=False):
206 def get_app_settings(cls, cache=False):
207
207
208 ret = cls.query()
208 ret = cls.query()
209
209
210 if cache:
210 if cache:
211 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
211 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
212
212
213 if not ret:
213 if not ret:
214 raise Exception('Could not get application settings !')
214 raise Exception('Could not get application settings !')
215 settings = {}
215 settings = {}
216 for each in ret:
216 for each in ret:
217 settings['rhodecode_' + each.app_settings_name] = \
217 settings['rhodecode_' + each.app_settings_name] = \
218 each.app_settings_value
218 each.app_settings_value
219
219
220 return settings
220 return settings
221
221
222 @classmethod
222 @classmethod
223 def get_ldap_settings(cls, cache=False):
223 def get_ldap_settings(cls, cache=False):
224 ret = cls.query()\
224 ret = cls.query()\
225 .filter(cls.app_settings_name.startswith('ldap_')).all()
225 .filter(cls.app_settings_name.startswith('ldap_')).all()
226 fd = {}
226 fd = {}
227 for row in ret:
227 for row in ret:
228 fd.update({row.app_settings_name: row.app_settings_value})
228 fd.update({row.app_settings_name: row.app_settings_value})
229
229
230 return fd
230 return fd
231
231
232 @classmethod
232 @classmethod
233 def get_default_repo_settings(cls, cache=False, strip_prefix=False):
233 def get_default_repo_settings(cls, cache=False, strip_prefix=False):
234 ret = cls.query()\
234 ret = cls.query()\
235 .filter(cls.app_settings_name.startswith('default_')).all()
235 .filter(cls.app_settings_name.startswith('default_')).all()
236 fd = {}
236 fd = {}
237 for row in ret:
237 for row in ret:
238 key = row.app_settings_name
238 key = row.app_settings_name
239 if strip_prefix:
239 if strip_prefix:
240 key = remove_prefix(key, prefix='default_')
240 key = remove_prefix(key, prefix='default_')
241 fd.update({key: row.app_settings_value})
241 fd.update({key: row.app_settings_value})
242
242
243 return fd
243 return fd
244
244
245
245
246 class RhodeCodeUi(Base, BaseModel):
246 class RhodeCodeUi(Base, BaseModel):
247 __tablename__ = 'rhodecode_ui'
247 __tablename__ = 'rhodecode_ui'
248 __table_args__ = (
248 __table_args__ = (
249 UniqueConstraint('ui_key'),
249 UniqueConstraint('ui_key'),
250 {'extend_existing': True, 'mysql_engine': 'InnoDB',
250 {'extend_existing': True, 'mysql_engine': 'InnoDB',
251 'mysql_charset': 'utf8'}
251 'mysql_charset': 'utf8'}
252 )
252 )
253
253
254 HOOK_UPDATE = 'changegroup.update'
254 HOOK_UPDATE = 'changegroup.update'
255 HOOK_REPO_SIZE = 'changegroup.repo_size'
255 HOOK_REPO_SIZE = 'changegroup.repo_size'
256 HOOK_PUSH = 'changegroup.push_logger'
256 HOOK_PUSH = 'changegroup.push_logger'
257 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
257 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
258 HOOK_PULL = 'outgoing.pull_logger'
258 HOOK_PULL = 'outgoing.pull_logger'
259 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
259 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
260
260
261 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
261 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
262 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
262 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
263 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
263 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
264 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
264 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
265 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
265 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
266
266
267 @classmethod
267 @classmethod
268 def get_by_key(cls, key):
268 def get_by_key(cls, key):
269 return cls.query().filter(cls.ui_key == key).scalar()
269 return cls.query().filter(cls.ui_key == key).scalar()
270
270
271 @classmethod
271 @classmethod
272 def get_builtin_hooks(cls):
272 def get_builtin_hooks(cls):
273 q = cls.query()
273 q = cls.query()
274 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
274 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
275 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
275 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
276 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
276 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
277 return q.all()
277 return q.all()
278
278
279 @classmethod
279 @classmethod
280 def get_custom_hooks(cls):
280 def get_custom_hooks(cls):
281 q = cls.query()
281 q = cls.query()
282 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
282 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
283 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
283 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
284 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
284 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
285 q = q.filter(cls.ui_section == 'hooks')
285 q = q.filter(cls.ui_section == 'hooks')
286 return q.all()
286 return q.all()
287
287
288 @classmethod
288 @classmethod
289 def get_repos_location(cls):
289 def get_repos_location(cls):
290 return cls.get_by_key('/').ui_value
290 return cls.get_by_key('/').ui_value
291
291
292 @classmethod
292 @classmethod
293 def create_or_update_hook(cls, key, val):
293 def create_or_update_hook(cls, key, val):
294 new_ui = cls.get_by_key(key) or cls()
294 new_ui = cls.get_by_key(key) or cls()
295 new_ui.ui_section = 'hooks'
295 new_ui.ui_section = 'hooks'
296 new_ui.ui_active = True
296 new_ui.ui_active = True
297 new_ui.ui_key = key
297 new_ui.ui_key = key
298 new_ui.ui_value = val
298 new_ui.ui_value = val
299
299
300 Session().add(new_ui)
300 Session().add(new_ui)
301
301
302 def __repr__(self):
302 def __repr__(self):
303 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
303 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
304 self.ui_value)
304 self.ui_value)
305
305
306
306
307 class User(Base, BaseModel):
307 class User(Base, BaseModel):
308 __tablename__ = 'users'
308 __tablename__ = 'users'
309 __table_args__ = (
309 __table_args__ = (
310 UniqueConstraint('username'), UniqueConstraint('email'),
310 UniqueConstraint('username'), UniqueConstraint('email'),
311 Index('u_username_idx', 'username'),
311 Index('u_username_idx', 'username'),
312 Index('u_email_idx', 'email'),
312 Index('u_email_idx', 'email'),
313 {'extend_existing': True, 'mysql_engine': 'InnoDB',
313 {'extend_existing': True, 'mysql_engine': 'InnoDB',
314 'mysql_charset': 'utf8'}
314 'mysql_charset': 'utf8'}
315 )
315 )
316 DEFAULT_USER = 'default'
316 DEFAULT_USER = 'default'
317 DEFAULT_PERMISSIONS = [
317 DEFAULT_PERMISSIONS = [
318 'hg.register.manual_activate', 'hg.create.repository',
318 'hg.register.manual_activate', 'hg.create.repository',
319 'hg.fork.repository', 'repository.read', 'group.read'
319 'hg.fork.repository', 'repository.read', 'group.read'
320 ]
320 ]
321 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
321 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
322 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
322 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
323 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
323 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
324 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
324 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
325 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
325 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
326 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
326 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
327 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
328 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
328 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
329 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
329 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
330 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
330 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
331 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
331 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
332 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
332 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
333
333
334 user_log = relationship('UserLog', cascade='all')
335 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
334 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
336
335
337 repositories = relationship('Repository')
336 repositories = relationship('Repository')
338 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
337 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
339 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
338 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
340 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
339 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
341
340
342 group_member = relationship('UsersGroupMember', cascade='all')
341 group_member = relationship('UsersGroupMember', cascade='all')
343
342
344 notifications = relationship('UserNotification', cascade='all')
343 notifications = relationship('UserNotification', cascade='all')
345 # notifications assigned to this user
344 # notifications assigned to this user
346 user_created_notifications = relationship('Notification', cascade='all')
345 user_created_notifications = relationship('Notification', cascade='all')
347 # comments created by this user
346 # comments created by this user
348 user_comments = relationship('ChangesetComment', cascade='all')
347 user_comments = relationship('ChangesetComment', cascade='all')
349 #extra emails for this user
348 #extra emails for this user
350 user_emails = relationship('UserEmailMap', cascade='all')
349 user_emails = relationship('UserEmailMap', cascade='all')
351
350
352 @hybrid_property
351 @hybrid_property
353 def email(self):
352 def email(self):
354 return self._email
353 return self._email
355
354
356 @email.setter
355 @email.setter
357 def email(self, val):
356 def email(self, val):
358 self._email = val.lower() if val else None
357 self._email = val.lower() if val else None
359
358
360 @property
359 @property
361 def firstname(self):
360 def firstname(self):
362 # alias for future
361 # alias for future
363 return self.name
362 return self.name
364
363
365 @property
364 @property
366 def emails(self):
365 def emails(self):
367 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
366 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
368 return [self.email] + [x.email for x in other]
367 return [self.email] + [x.email for x in other]
369
368
370 @property
369 @property
371 def username_and_name(self):
370 def username_and_name(self):
372 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
371 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
373
372
374 @property
373 @property
375 def full_name(self):
374 def full_name(self):
376 return '%s %s' % (self.firstname, self.lastname)
375 return '%s %s' % (self.firstname, self.lastname)
377
376
378 @property
377 @property
379 def full_name_or_username(self):
378 def full_name_or_username(self):
380 return ('%s %s' % (self.firstname, self.lastname)
379 return ('%s %s' % (self.firstname, self.lastname)
381 if (self.firstname and self.lastname) else self.username)
380 if (self.firstname and self.lastname) else self.username)
382
381
383 @property
382 @property
384 def full_contact(self):
383 def full_contact(self):
385 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
384 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
386
385
387 @property
386 @property
388 def short_contact(self):
387 def short_contact(self):
389 return '%s %s' % (self.firstname, self.lastname)
388 return '%s %s' % (self.firstname, self.lastname)
390
389
391 @property
390 @property
392 def is_admin(self):
391 def is_admin(self):
393 return self.admin
392 return self.admin
394
393
395 def __unicode__(self):
394 def __unicode__(self):
396 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
395 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
397 self.user_id, self.username)
396 self.user_id, self.username)
398
397
399 @classmethod
398 @classmethod
400 def get_by_username(cls, username, case_insensitive=False, cache=False):
399 def get_by_username(cls, username, case_insensitive=False, cache=False):
401 if case_insensitive:
400 if case_insensitive:
402 q = cls.query().filter(cls.username.ilike(username))
401 q = cls.query().filter(cls.username.ilike(username))
403 else:
402 else:
404 q = cls.query().filter(cls.username == username)
403 q = cls.query().filter(cls.username == username)
405
404
406 if cache:
405 if cache:
407 q = q.options(FromCache(
406 q = q.options(FromCache(
408 "sql_cache_short",
407 "sql_cache_short",
409 "get_user_%s" % _hash_key(username)
408 "get_user_%s" % _hash_key(username)
410 )
409 )
411 )
410 )
412 return q.scalar()
411 return q.scalar()
413
412
414 @classmethod
413 @classmethod
415 def get_by_api_key(cls, api_key, cache=False):
414 def get_by_api_key(cls, api_key, cache=False):
416 q = cls.query().filter(cls.api_key == api_key)
415 q = cls.query().filter(cls.api_key == api_key)
417
416
418 if cache:
417 if cache:
419 q = q.options(FromCache("sql_cache_short",
418 q = q.options(FromCache("sql_cache_short",
420 "get_api_key_%s" % api_key))
419 "get_api_key_%s" % api_key))
421 return q.scalar()
420 return q.scalar()
422
421
423 @classmethod
422 @classmethod
424 def get_by_email(cls, email, case_insensitive=False, cache=False):
423 def get_by_email(cls, email, case_insensitive=False, cache=False):
425 if case_insensitive:
424 if case_insensitive:
426 q = cls.query().filter(cls.email.ilike(email))
425 q = cls.query().filter(cls.email.ilike(email))
427 else:
426 else:
428 q = cls.query().filter(cls.email == email)
427 q = cls.query().filter(cls.email == email)
429
428
430 if cache:
429 if cache:
431 q = q.options(FromCache("sql_cache_short",
430 q = q.options(FromCache("sql_cache_short",
432 "get_email_key_%s" % email))
431 "get_email_key_%s" % email))
433
432
434 ret = q.scalar()
433 ret = q.scalar()
435 if ret is None:
434 if ret is None:
436 q = UserEmailMap.query()
435 q = UserEmailMap.query()
437 # try fetching in alternate email map
436 # try fetching in alternate email map
438 if case_insensitive:
437 if case_insensitive:
439 q = q.filter(UserEmailMap.email.ilike(email))
438 q = q.filter(UserEmailMap.email.ilike(email))
440 else:
439 else:
441 q = q.filter(UserEmailMap.email == email)
440 q = q.filter(UserEmailMap.email == email)
442 q = q.options(joinedload(UserEmailMap.user))
441 q = q.options(joinedload(UserEmailMap.user))
443 if cache:
442 if cache:
444 q = q.options(FromCache("sql_cache_short",
443 q = q.options(FromCache("sql_cache_short",
445 "get_email_map_key_%s" % email))
444 "get_email_map_key_%s" % email))
446 ret = getattr(q.scalar(), 'user', None)
445 ret = getattr(q.scalar(), 'user', None)
447
446
448 return ret
447 return ret
449
448
450 def update_lastlogin(self):
449 def update_lastlogin(self):
451 """Update user lastlogin"""
450 """Update user lastlogin"""
452 self.last_login = datetime.datetime.now()
451 self.last_login = datetime.datetime.now()
453 Session().add(self)
452 Session().add(self)
454 log.debug('updated user %s lastlogin' % self.username)
453 log.debug('updated user %s lastlogin' % self.username)
455
454
456 def get_api_data(self):
455 def get_api_data(self):
457 """
456 """
458 Common function for generating user related data for API
457 Common function for generating user related data for API
459 """
458 """
460 user = self
459 user = self
461 data = dict(
460 data = dict(
462 user_id=user.user_id,
461 user_id=user.user_id,
463 username=user.username,
462 username=user.username,
464 firstname=user.name,
463 firstname=user.name,
465 lastname=user.lastname,
464 lastname=user.lastname,
466 email=user.email,
465 email=user.email,
467 emails=user.emails,
466 emails=user.emails,
468 api_key=user.api_key,
467 api_key=user.api_key,
469 active=user.active,
468 active=user.active,
470 admin=user.admin,
469 admin=user.admin,
471 ldap_dn=user.ldap_dn,
470 ldap_dn=user.ldap_dn,
472 last_login=user.last_login,
471 last_login=user.last_login,
473 )
472 )
474 return data
473 return data
475
474
476 def __json__(self):
475 def __json__(self):
477 data = dict(
476 data = dict(
478 full_name=self.full_name,
477 full_name=self.full_name,
479 full_name_or_username=self.full_name_or_username,
478 full_name_or_username=self.full_name_or_username,
480 short_contact=self.short_contact,
479 short_contact=self.short_contact,
481 full_contact=self.full_contact
480 full_contact=self.full_contact
482 )
481 )
483 data.update(self.get_api_data())
482 data.update(self.get_api_data())
484 return data
483 return data
485
484
486
485
487 class UserEmailMap(Base, BaseModel):
486 class UserEmailMap(Base, BaseModel):
488 __tablename__ = 'user_email_map'
487 __tablename__ = 'user_email_map'
489 __table_args__ = (
488 __table_args__ = (
490 Index('uem_email_idx', 'email'),
489 Index('uem_email_idx', 'email'),
491 UniqueConstraint('email'),
490 UniqueConstraint('email'),
492 {'extend_existing': True, 'mysql_engine': 'InnoDB',
491 {'extend_existing': True, 'mysql_engine': 'InnoDB',
493 'mysql_charset': 'utf8'}
492 'mysql_charset': 'utf8'}
494 )
493 )
495 __mapper_args__ = {}
494 __mapper_args__ = {}
496
495
497 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
496 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
498 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
497 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
499 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
498 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
500 user = relationship('User', lazy='joined')
499 user = relationship('User', lazy='joined')
501
500
502 @validates('_email')
501 @validates('_email')
503 def validate_email(self, key, email):
502 def validate_email(self, key, email):
504 # check if this email is not main one
503 # check if this email is not main one
505 main_email = Session().query(User).filter(User.email == email).scalar()
504 main_email = Session().query(User).filter(User.email == email).scalar()
506 if main_email is not None:
505 if main_email is not None:
507 raise AttributeError('email %s is present is user table' % email)
506 raise AttributeError('email %s is present is user table' % email)
508 return email
507 return email
509
508
510 @hybrid_property
509 @hybrid_property
511 def email(self):
510 def email(self):
512 return self._email
511 return self._email
513
512
514 @email.setter
513 @email.setter
515 def email(self, val):
514 def email(self, val):
516 self._email = val.lower() if val else None
515 self._email = val.lower() if val else None
517
516
518
517
519 class UserLog(Base, BaseModel):
518 class UserLog(Base, BaseModel):
520 __tablename__ = 'user_logs'
519 __tablename__ = 'user_logs'
521 __table_args__ = (
520 __table_args__ = (
522 {'extend_existing': True, 'mysql_engine': 'InnoDB',
521 {'extend_existing': True, 'mysql_engine': 'InnoDB',
523 'mysql_charset': 'utf8'},
522 'mysql_charset': 'utf8'},
524 )
523 )
525 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
524 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
526 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
525 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
526 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
527 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
527 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
528 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
528 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
529 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
529 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
530 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
530 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
531 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
531 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
532
532
533 @property
533 @property
534 def action_as_day(self):
534 def action_as_day(self):
535 return datetime.date(*self.action_date.timetuple()[:3])
535 return datetime.date(*self.action_date.timetuple()[:3])
536
536
537 user = relationship('User')
537 user = relationship('User')
538 repository = relationship('Repository', cascade='')
538 repository = relationship('Repository', cascade='')
539
539
540
540
541 class UsersGroup(Base, BaseModel):
541 class UsersGroup(Base, BaseModel):
542 __tablename__ = 'users_groups'
542 __tablename__ = 'users_groups'
543 __table_args__ = (
543 __table_args__ = (
544 {'extend_existing': True, 'mysql_engine': 'InnoDB',
544 {'extend_existing': True, 'mysql_engine': 'InnoDB',
545 'mysql_charset': 'utf8'},
545 'mysql_charset': 'utf8'},
546 )
546 )
547
547
548 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
548 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
549 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
549 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
550 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
550 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
551 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
551 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
552
552
553 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
553 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
554 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
554 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
555 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
555 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
556
556
557 def __unicode__(self):
557 def __unicode__(self):
558 return u'<userGroup(%s)>' % (self.users_group_name)
558 return u'<userGroup(%s)>' % (self.users_group_name)
559
559
560 @classmethod
560 @classmethod
561 def get_by_group_name(cls, group_name, cache=False,
561 def get_by_group_name(cls, group_name, cache=False,
562 case_insensitive=False):
562 case_insensitive=False):
563 if case_insensitive:
563 if case_insensitive:
564 q = cls.query().filter(cls.users_group_name.ilike(group_name))
564 q = cls.query().filter(cls.users_group_name.ilike(group_name))
565 else:
565 else:
566 q = cls.query().filter(cls.users_group_name == group_name)
566 q = cls.query().filter(cls.users_group_name == group_name)
567 if cache:
567 if cache:
568 q = q.options(FromCache(
568 q = q.options(FromCache(
569 "sql_cache_short",
569 "sql_cache_short",
570 "get_user_%s" % _hash_key(group_name)
570 "get_user_%s" % _hash_key(group_name)
571 )
571 )
572 )
572 )
573 return q.scalar()
573 return q.scalar()
574
574
575 @classmethod
575 @classmethod
576 def get(cls, users_group_id, cache=False):
576 def get(cls, users_group_id, cache=False):
577 users_group = cls.query()
577 users_group = cls.query()
578 if cache:
578 if cache:
579 users_group = users_group.options(FromCache("sql_cache_short",
579 users_group = users_group.options(FromCache("sql_cache_short",
580 "get_users_group_%s" % users_group_id))
580 "get_users_group_%s" % users_group_id))
581 return users_group.get(users_group_id)
581 return users_group.get(users_group_id)
582
582
583 def get_api_data(self):
583 def get_api_data(self):
584 users_group = self
584 users_group = self
585
585
586 data = dict(
586 data = dict(
587 users_group_id=users_group.users_group_id,
587 users_group_id=users_group.users_group_id,
588 group_name=users_group.users_group_name,
588 group_name=users_group.users_group_name,
589 active=users_group.users_group_active,
589 active=users_group.users_group_active,
590 )
590 )
591
591
592 return data
592 return data
593
593
594
594
595 class UsersGroupMember(Base, BaseModel):
595 class UsersGroupMember(Base, BaseModel):
596 __tablename__ = 'users_groups_members'
596 __tablename__ = 'users_groups_members'
597 __table_args__ = (
597 __table_args__ = (
598 {'extend_existing': True, 'mysql_engine': 'InnoDB',
598 {'extend_existing': True, 'mysql_engine': 'InnoDB',
599 'mysql_charset': 'utf8'},
599 'mysql_charset': 'utf8'},
600 )
600 )
601
601
602 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
602 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
603 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
603 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
604 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
604 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
605
605
606 user = relationship('User', lazy='joined')
606 user = relationship('User', lazy='joined')
607 users_group = relationship('UsersGroup')
607 users_group = relationship('UsersGroup')
608
608
609 def __init__(self, gr_id='', u_id=''):
609 def __init__(self, gr_id='', u_id=''):
610 self.users_group_id = gr_id
610 self.users_group_id = gr_id
611 self.user_id = u_id
611 self.user_id = u_id
612
612
613
613
614 class Repository(Base, BaseModel):
614 class Repository(Base, BaseModel):
615 __tablename__ = 'repositories'
615 __tablename__ = 'repositories'
616 __table_args__ = (
616 __table_args__ = (
617 UniqueConstraint('repo_name'),
617 UniqueConstraint('repo_name'),
618 Index('r_repo_name_idx', 'repo_name'),
618 Index('r_repo_name_idx', 'repo_name'),
619 {'extend_existing': True, 'mysql_engine': 'InnoDB',
619 {'extend_existing': True, 'mysql_engine': 'InnoDB',
620 'mysql_charset': 'utf8'},
620 'mysql_charset': 'utf8'},
621 )
621 )
622
622
623 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
623 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
624 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
624 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
625 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
625 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
626 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
626 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
627 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
627 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
628 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
628 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
629 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
629 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
630 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
630 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
631 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
631 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
632 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
632 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
633 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
633 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
634 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
634 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
635 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
635 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
636 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
636 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
637
637
638 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
638 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
639 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
639 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
640
640
641 user = relationship('User')
641 user = relationship('User')
642 fork = relationship('Repository', remote_side=repo_id)
642 fork = relationship('Repository', remote_side=repo_id)
643 group = relationship('RepoGroup')
643 group = relationship('RepoGroup')
644 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
644 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
645 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
645 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
646 stats = relationship('Statistics', cascade='all', uselist=False)
646 stats = relationship('Statistics', cascade='all', uselist=False)
647
647
648 followers = relationship('UserFollowing',
648 followers = relationship('UserFollowing',
649 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
649 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
650 cascade='all')
650 cascade='all')
651
651
652 logs = relationship('UserLog')
652 logs = relationship('UserLog')
653 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
653 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
654
654
655 pull_requests_org = relationship('PullRequest',
655 pull_requests_org = relationship('PullRequest',
656 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
656 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
657 cascade="all, delete, delete-orphan")
657 cascade="all, delete, delete-orphan")
658
658
659 pull_requests_other = relationship('PullRequest',
659 pull_requests_other = relationship('PullRequest',
660 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
660 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
661 cascade="all, delete, delete-orphan")
661 cascade="all, delete, delete-orphan")
662
662
663 def __unicode__(self):
663 def __unicode__(self):
664 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
664 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
665 self.repo_name)
665 self.repo_name)
666
666
667 @hybrid_property
667 @hybrid_property
668 def locked(self):
668 def locked(self):
669 # always should return [user_id, timelocked]
669 # always should return [user_id, timelocked]
670 if self._locked:
670 if self._locked:
671 _lock_info = self._locked.split(':')
671 _lock_info = self._locked.split(':')
672 return int(_lock_info[0]), _lock_info[1]
672 return int(_lock_info[0]), _lock_info[1]
673 return [None, None]
673 return [None, None]
674
674
675 @locked.setter
675 @locked.setter
676 def locked(self, val):
676 def locked(self, val):
677 if val and isinstance(val, (list, tuple)):
677 if val and isinstance(val, (list, tuple)):
678 self._locked = ':'.join(map(str, val))
678 self._locked = ':'.join(map(str, val))
679 else:
679 else:
680 self._locked = None
680 self._locked = None
681
681
682 @classmethod
682 @classmethod
683 def url_sep(cls):
683 def url_sep(cls):
684 return URL_SEP
684 return URL_SEP
685
685
686 @classmethod
686 @classmethod
687 def get_by_repo_name(cls, repo_name):
687 def get_by_repo_name(cls, repo_name):
688 q = Session().query(cls).filter(cls.repo_name == repo_name)
688 q = Session().query(cls).filter(cls.repo_name == repo_name)
689 q = q.options(joinedload(Repository.fork))\
689 q = q.options(joinedload(Repository.fork))\
690 .options(joinedload(Repository.user))\
690 .options(joinedload(Repository.user))\
691 .options(joinedload(Repository.group))
691 .options(joinedload(Repository.group))
692 return q.scalar()
692 return q.scalar()
693
693
694 @classmethod
694 @classmethod
695 def get_by_full_path(cls, repo_full_path):
695 def get_by_full_path(cls, repo_full_path):
696 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
696 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
697 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
697 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
698
698
699 @classmethod
699 @classmethod
700 def get_repo_forks(cls, repo_id):
700 def get_repo_forks(cls, repo_id):
701 return cls.query().filter(Repository.fork_id == repo_id)
701 return cls.query().filter(Repository.fork_id == repo_id)
702
702
703 @classmethod
703 @classmethod
704 def base_path(cls):
704 def base_path(cls):
705 """
705 """
706 Returns base path when all repos are stored
706 Returns base path when all repos are stored
707
707
708 :param cls:
708 :param cls:
709 """
709 """
710 q = Session().query(RhodeCodeUi)\
710 q = Session().query(RhodeCodeUi)\
711 .filter(RhodeCodeUi.ui_key == cls.url_sep())
711 .filter(RhodeCodeUi.ui_key == cls.url_sep())
712 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
712 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
713 return q.one().ui_value
713 return q.one().ui_value
714
714
715 @property
715 @property
716 def forks(self):
716 def forks(self):
717 """
717 """
718 Return forks of this repo
718 Return forks of this repo
719 """
719 """
720 return Repository.get_repo_forks(self.repo_id)
720 return Repository.get_repo_forks(self.repo_id)
721
721
722 @property
722 @property
723 def parent(self):
723 def parent(self):
724 """
724 """
725 Returns fork parent
725 Returns fork parent
726 """
726 """
727 return self.fork
727 return self.fork
728
728
729 @property
729 @property
730 def just_name(self):
730 def just_name(self):
731 return self.repo_name.split(Repository.url_sep())[-1]
731 return self.repo_name.split(Repository.url_sep())[-1]
732
732
733 @property
733 @property
734 def groups_with_parents(self):
734 def groups_with_parents(self):
735 groups = []
735 groups = []
736 if self.group is None:
736 if self.group is None:
737 return groups
737 return groups
738
738
739 cur_gr = self.group
739 cur_gr = self.group
740 groups.insert(0, cur_gr)
740 groups.insert(0, cur_gr)
741 while 1:
741 while 1:
742 gr = getattr(cur_gr, 'parent_group', None)
742 gr = getattr(cur_gr, 'parent_group', None)
743 cur_gr = cur_gr.parent_group
743 cur_gr = cur_gr.parent_group
744 if gr is None:
744 if gr is None:
745 break
745 break
746 groups.insert(0, gr)
746 groups.insert(0, gr)
747
747
748 return groups
748 return groups
749
749
750 @property
750 @property
751 def groups_and_repo(self):
751 def groups_and_repo(self):
752 return self.groups_with_parents, self.just_name
752 return self.groups_with_parents, self.just_name
753
753
754 @LazyProperty
754 @LazyProperty
755 def repo_path(self):
755 def repo_path(self):
756 """
756 """
757 Returns base full path for that repository means where it actually
757 Returns base full path for that repository means where it actually
758 exists on a filesystem
758 exists on a filesystem
759 """
759 """
760 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
760 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
761 Repository.url_sep())
761 Repository.url_sep())
762 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
762 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
763 return q.one().ui_value
763 return q.one().ui_value
764
764
765 @property
765 @property
766 def repo_full_path(self):
766 def repo_full_path(self):
767 p = [self.repo_path]
767 p = [self.repo_path]
768 # we need to split the name by / since this is how we store the
768 # we need to split the name by / since this is how we store the
769 # names in the database, but that eventually needs to be converted
769 # names in the database, but that eventually needs to be converted
770 # into a valid system path
770 # into a valid system path
771 p += self.repo_name.split(Repository.url_sep())
771 p += self.repo_name.split(Repository.url_sep())
772 return os.path.join(*p)
772 return os.path.join(*p)
773
773
774 @property
774 @property
775 def cache_keys(self):
775 def cache_keys(self):
776 """
776 """
777 Returns associated cache keys for that repo
777 Returns associated cache keys for that repo
778 """
778 """
779 return CacheInvalidation.query()\
779 return CacheInvalidation.query()\
780 .filter(CacheInvalidation.cache_args == self.repo_name)\
780 .filter(CacheInvalidation.cache_args == self.repo_name)\
781 .order_by(CacheInvalidation.cache_key)\
781 .order_by(CacheInvalidation.cache_key)\
782 .all()
782 .all()
783
783
784 def get_new_name(self, repo_name):
784 def get_new_name(self, repo_name):
785 """
785 """
786 returns new full repository name based on assigned group and new new
786 returns new full repository name based on assigned group and new new
787
787
788 :param group_name:
788 :param group_name:
789 """
789 """
790 path_prefix = self.group.full_path_splitted if self.group else []
790 path_prefix = self.group.full_path_splitted if self.group else []
791 return Repository.url_sep().join(path_prefix + [repo_name])
791 return Repository.url_sep().join(path_prefix + [repo_name])
792
792
793 @property
793 @property
794 def _ui(self):
794 def _ui(self):
795 """
795 """
796 Creates an db based ui object for this repository
796 Creates an db based ui object for this repository
797 """
797 """
798 from rhodecode.lib.utils import make_ui
798 from rhodecode.lib.utils import make_ui
799 return make_ui('db', clear_session=False)
799 return make_ui('db', clear_session=False)
800
800
801 @classmethod
801 @classmethod
802 def inject_ui(cls, repo, extras={}):
802 def inject_ui(cls, repo, extras={}):
803 from rhodecode.lib.vcs.backends.hg import MercurialRepository
803 from rhodecode.lib.vcs.backends.hg import MercurialRepository
804 from rhodecode.lib.vcs.backends.git import GitRepository
804 from rhodecode.lib.vcs.backends.git import GitRepository
805 required = (MercurialRepository, GitRepository)
805 required = (MercurialRepository, GitRepository)
806 if not isinstance(repo, required):
806 if not isinstance(repo, required):
807 raise Exception('repo must be instance of %s' % required)
807 raise Exception('repo must be instance of %s' % required)
808
808
809 # inject ui extra param to log this action via push logger
809 # inject ui extra param to log this action via push logger
810 for k, v in extras.items():
810 for k, v in extras.items():
811 repo._repo.ui.setconfig('rhodecode_extras', k, v)
811 repo._repo.ui.setconfig('rhodecode_extras', k, v)
812
812
813 @classmethod
813 @classmethod
814 def is_valid(cls, repo_name):
814 def is_valid(cls, repo_name):
815 """
815 """
816 returns True if given repo name is a valid filesystem repository
816 returns True if given repo name is a valid filesystem repository
817
817
818 :param cls:
818 :param cls:
819 :param repo_name:
819 :param repo_name:
820 """
820 """
821 from rhodecode.lib.utils import is_valid_repo
821 from rhodecode.lib.utils import is_valid_repo
822
822
823 return is_valid_repo(repo_name, cls.base_path())
823 return is_valid_repo(repo_name, cls.base_path())
824
824
825 def get_api_data(self):
825 def get_api_data(self):
826 """
826 """
827 Common function for generating repo api data
827 Common function for generating repo api data
828
828
829 """
829 """
830 repo = self
830 repo = self
831 data = dict(
831 data = dict(
832 repo_id=repo.repo_id,
832 repo_id=repo.repo_id,
833 repo_name=repo.repo_name,
833 repo_name=repo.repo_name,
834 repo_type=repo.repo_type,
834 repo_type=repo.repo_type,
835 clone_uri=repo.clone_uri,
835 clone_uri=repo.clone_uri,
836 private=repo.private,
836 private=repo.private,
837 created_on=repo.created_on,
837 created_on=repo.created_on,
838 description=repo.description,
838 description=repo.description,
839 landing_rev=repo.landing_rev,
839 landing_rev=repo.landing_rev,
840 owner=repo.user.username,
840 owner=repo.user.username,
841 fork_of=repo.fork.repo_name if repo.fork else None
841 fork_of=repo.fork.repo_name if repo.fork else None
842 )
842 )
843
843
844 return data
844 return data
845
845
846 @classmethod
846 @classmethod
847 def lock(cls, repo, user_id):
847 def lock(cls, repo, user_id):
848 repo.locked = [user_id, time.time()]
848 repo.locked = [user_id, time.time()]
849 Session().add(repo)
849 Session().add(repo)
850 Session().commit()
850 Session().commit()
851
851
852 @classmethod
852 @classmethod
853 def unlock(cls, repo):
853 def unlock(cls, repo):
854 repo.locked = None
854 repo.locked = None
855 Session().add(repo)
855 Session().add(repo)
856 Session().commit()
856 Session().commit()
857
857
858 @property
858 @property
859 def last_db_change(self):
859 def last_db_change(self):
860 return self.updated_on
860 return self.updated_on
861
861
862 #==========================================================================
862 #==========================================================================
863 # SCM PROPERTIES
863 # SCM PROPERTIES
864 #==========================================================================
864 #==========================================================================
865
865
866 def get_changeset(self, rev=None):
866 def get_changeset(self, rev=None):
867 return get_changeset_safe(self.scm_instance, rev)
867 return get_changeset_safe(self.scm_instance, rev)
868
868
869 def get_landing_changeset(self):
869 def get_landing_changeset(self):
870 """
870 """
871 Returns landing changeset, or if that doesn't exist returns the tip
871 Returns landing changeset, or if that doesn't exist returns the tip
872 """
872 """
873 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
873 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
874 return cs
874 return cs
875
875
876 def update_last_change(self, last_change=None):
876 def update_last_change(self, last_change=None):
877 if last_change is None:
877 if last_change is None:
878 last_change = datetime.datetime.now()
878 last_change = datetime.datetime.now()
879 if self.updated_on is None or self.updated_on != last_change:
879 if self.updated_on is None or self.updated_on != last_change:
880 log.debug('updated repo %s with new date %s' % (self, last_change))
880 log.debug('updated repo %s with new date %s' % (self, last_change))
881 self.updated_on = last_change
881 self.updated_on = last_change
882 Session().add(self)
882 Session().add(self)
883 Session().commit()
883 Session().commit()
884
884
885 @property
885 @property
886 def tip(self):
886 def tip(self):
887 return self.get_changeset('tip')
887 return self.get_changeset('tip')
888
888
889 @property
889 @property
890 def author(self):
890 def author(self):
891 return self.tip.author
891 return self.tip.author
892
892
893 @property
893 @property
894 def last_change(self):
894 def last_change(self):
895 return self.scm_instance.last_change
895 return self.scm_instance.last_change
896
896
897 def get_comments(self, revisions=None):
897 def get_comments(self, revisions=None):
898 """
898 """
899 Returns comments for this repository grouped by revisions
899 Returns comments for this repository grouped by revisions
900
900
901 :param revisions: filter query by revisions only
901 :param revisions: filter query by revisions only
902 """
902 """
903 cmts = ChangesetComment.query()\
903 cmts = ChangesetComment.query()\
904 .filter(ChangesetComment.repo == self)
904 .filter(ChangesetComment.repo == self)
905 if revisions:
905 if revisions:
906 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
906 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
907 grouped = defaultdict(list)
907 grouped = defaultdict(list)
908 for cmt in cmts.all():
908 for cmt in cmts.all():
909 grouped[cmt.revision].append(cmt)
909 grouped[cmt.revision].append(cmt)
910 return grouped
910 return grouped
911
911
912 def statuses(self, revisions=None):
912 def statuses(self, revisions=None):
913 """
913 """
914 Returns statuses for this repository
914 Returns statuses for this repository
915
915
916 :param revisions: list of revisions to get statuses for
916 :param revisions: list of revisions to get statuses for
917 :type revisions: list
917 :type revisions: list
918 """
918 """
919
919
920 statuses = ChangesetStatus.query()\
920 statuses = ChangesetStatus.query()\
921 .filter(ChangesetStatus.repo == self)\
921 .filter(ChangesetStatus.repo == self)\
922 .filter(ChangesetStatus.version == 0)
922 .filter(ChangesetStatus.version == 0)
923 if revisions:
923 if revisions:
924 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
924 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
925 grouped = {}
925 grouped = {}
926
926
927 #maybe we have open new pullrequest without a status ?
927 #maybe we have open new pullrequest without a status ?
928 stat = ChangesetStatus.STATUS_UNDER_REVIEW
928 stat = ChangesetStatus.STATUS_UNDER_REVIEW
929 status_lbl = ChangesetStatus.get_status_lbl(stat)
929 status_lbl = ChangesetStatus.get_status_lbl(stat)
930 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
930 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
931 for rev in pr.revisions:
931 for rev in pr.revisions:
932 pr_id = pr.pull_request_id
932 pr_id = pr.pull_request_id
933 pr_repo = pr.other_repo.repo_name
933 pr_repo = pr.other_repo.repo_name
934 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
934 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
935
935
936 for stat in statuses.all():
936 for stat in statuses.all():
937 pr_id = pr_repo = None
937 pr_id = pr_repo = None
938 if stat.pull_request:
938 if stat.pull_request:
939 pr_id = stat.pull_request.pull_request_id
939 pr_id = stat.pull_request.pull_request_id
940 pr_repo = stat.pull_request.other_repo.repo_name
940 pr_repo = stat.pull_request.other_repo.repo_name
941 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
941 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
942 pr_id, pr_repo]
942 pr_id, pr_repo]
943 return grouped
943 return grouped
944
944
945 #==========================================================================
945 #==========================================================================
946 # SCM CACHE INSTANCE
946 # SCM CACHE INSTANCE
947 #==========================================================================
947 #==========================================================================
948
948
949 @property
949 @property
950 def invalidate(self):
950 def invalidate(self):
951 return CacheInvalidation.invalidate(self.repo_name)
951 return CacheInvalidation.invalidate(self.repo_name)
952
952
953 def set_invalidate(self):
953 def set_invalidate(self):
954 """
954 """
955 set a cache for invalidation for this instance
955 set a cache for invalidation for this instance
956 """
956 """
957 CacheInvalidation.set_invalidate(repo_name=self.repo_name)
957 CacheInvalidation.set_invalidate(repo_name=self.repo_name)
958
958
959 @LazyProperty
959 @LazyProperty
960 def scm_instance(self):
960 def scm_instance(self):
961 import rhodecode
961 import rhodecode
962 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
962 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
963 if full_cache:
963 if full_cache:
964 return self.scm_instance_cached()
964 return self.scm_instance_cached()
965 return self.__get_instance()
965 return self.__get_instance()
966
966
967 def scm_instance_cached(self, cache_map=None):
967 def scm_instance_cached(self, cache_map=None):
968 @cache_region('long_term')
968 @cache_region('long_term')
969 def _c(repo_name):
969 def _c(repo_name):
970 return self.__get_instance()
970 return self.__get_instance()
971 rn = self.repo_name
971 rn = self.repo_name
972 log.debug('Getting cached instance of repo')
972 log.debug('Getting cached instance of repo')
973
973
974 if cache_map:
974 if cache_map:
975 # get using prefilled cache_map
975 # get using prefilled cache_map
976 invalidate_repo = cache_map[self.repo_name]
976 invalidate_repo = cache_map[self.repo_name]
977 if invalidate_repo:
977 if invalidate_repo:
978 invalidate_repo = (None if invalidate_repo.cache_active
978 invalidate_repo = (None if invalidate_repo.cache_active
979 else invalidate_repo)
979 else invalidate_repo)
980 else:
980 else:
981 # get from invalidate
981 # get from invalidate
982 invalidate_repo = self.invalidate
982 invalidate_repo = self.invalidate
983
983
984 if invalidate_repo is not None:
984 if invalidate_repo is not None:
985 region_invalidate(_c, None, rn)
985 region_invalidate(_c, None, rn)
986 # update our cache
986 # update our cache
987 CacheInvalidation.set_valid(invalidate_repo.cache_key)
987 CacheInvalidation.set_valid(invalidate_repo.cache_key)
988 return _c(rn)
988 return _c(rn)
989
989
990 def __get_instance(self):
990 def __get_instance(self):
991 repo_full_path = self.repo_full_path
991 repo_full_path = self.repo_full_path
992 try:
992 try:
993 alias = get_scm(repo_full_path)[0]
993 alias = get_scm(repo_full_path)[0]
994 log.debug('Creating instance of %s repository' % alias)
994 log.debug('Creating instance of %s repository' % alias)
995 backend = get_backend(alias)
995 backend = get_backend(alias)
996 except VCSError:
996 except VCSError:
997 log.error(traceback.format_exc())
997 log.error(traceback.format_exc())
998 log.error('Perhaps this repository is in db and not in '
998 log.error('Perhaps this repository is in db and not in '
999 'filesystem run rescan repositories with '
999 'filesystem run rescan repositories with '
1000 '"destroy old data " option from admin panel')
1000 '"destroy old data " option from admin panel')
1001 return
1001 return
1002
1002
1003 if alias == 'hg':
1003 if alias == 'hg':
1004
1004
1005 repo = backend(safe_str(repo_full_path), create=False,
1005 repo = backend(safe_str(repo_full_path), create=False,
1006 baseui=self._ui)
1006 baseui=self._ui)
1007 # skip hidden web repository
1007 # skip hidden web repository
1008 if repo._get_hidden():
1008 if repo._get_hidden():
1009 return
1009 return
1010 else:
1010 else:
1011 repo = backend(repo_full_path, create=False)
1011 repo = backend(repo_full_path, create=False)
1012
1012
1013 return repo
1013 return repo
1014
1014
1015
1015
1016 class RepoGroup(Base, BaseModel):
1016 class RepoGroup(Base, BaseModel):
1017 __tablename__ = 'groups'
1017 __tablename__ = 'groups'
1018 __table_args__ = (
1018 __table_args__ = (
1019 UniqueConstraint('group_name', 'group_parent_id'),
1019 UniqueConstraint('group_name', 'group_parent_id'),
1020 CheckConstraint('group_id != group_parent_id'),
1020 CheckConstraint('group_id != group_parent_id'),
1021 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1021 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1022 'mysql_charset': 'utf8'},
1022 'mysql_charset': 'utf8'},
1023 )
1023 )
1024 __mapper_args__ = {'order_by': 'group_name'}
1024 __mapper_args__ = {'order_by': 'group_name'}
1025
1025
1026 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1026 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1027 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1027 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1028 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1028 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1029 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1029 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1030 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1030 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1031
1031
1032 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1032 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1033 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
1033 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
1034
1034
1035 parent_group = relationship('RepoGroup', remote_side=group_id)
1035 parent_group = relationship('RepoGroup', remote_side=group_id)
1036
1036
1037 def __init__(self, group_name='', parent_group=None):
1037 def __init__(self, group_name='', parent_group=None):
1038 self.group_name = group_name
1038 self.group_name = group_name
1039 self.parent_group = parent_group
1039 self.parent_group = parent_group
1040
1040
1041 def __unicode__(self):
1041 def __unicode__(self):
1042 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
1042 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
1043 self.group_name)
1043 self.group_name)
1044
1044
1045 @classmethod
1045 @classmethod
1046 def groups_choices(cls, check_perms=False):
1046 def groups_choices(cls, check_perms=False):
1047 from webhelpers.html import literal as _literal
1047 from webhelpers.html import literal as _literal
1048 from rhodecode.model.scm import ScmModel
1048 from rhodecode.model.scm import ScmModel
1049 groups = cls.query().all()
1049 groups = cls.query().all()
1050 if check_perms:
1050 if check_perms:
1051 #filter group user have access to, it's done
1051 #filter group user have access to, it's done
1052 #magically inside ScmModel based on current user
1052 #magically inside ScmModel based on current user
1053 groups = ScmModel().get_repos_groups(groups)
1053 groups = ScmModel().get_repos_groups(groups)
1054 repo_groups = [('', '')]
1054 repo_groups = [('', '')]
1055 sep = ' &raquo; '
1055 sep = ' &raquo; '
1056 _name = lambda k: _literal(sep.join(k))
1056 _name = lambda k: _literal(sep.join(k))
1057
1057
1058 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1058 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1059 for x in groups])
1059 for x in groups])
1060
1060
1061 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1061 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1062 return repo_groups
1062 return repo_groups
1063
1063
1064 @classmethod
1064 @classmethod
1065 def url_sep(cls):
1065 def url_sep(cls):
1066 return URL_SEP
1066 return URL_SEP
1067
1067
1068 @classmethod
1068 @classmethod
1069 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1069 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1070 if case_insensitive:
1070 if case_insensitive:
1071 gr = cls.query()\
1071 gr = cls.query()\
1072 .filter(cls.group_name.ilike(group_name))
1072 .filter(cls.group_name.ilike(group_name))
1073 else:
1073 else:
1074 gr = cls.query()\
1074 gr = cls.query()\
1075 .filter(cls.group_name == group_name)
1075 .filter(cls.group_name == group_name)
1076 if cache:
1076 if cache:
1077 gr = gr.options(FromCache(
1077 gr = gr.options(FromCache(
1078 "sql_cache_short",
1078 "sql_cache_short",
1079 "get_group_%s" % _hash_key(group_name)
1079 "get_group_%s" % _hash_key(group_name)
1080 )
1080 )
1081 )
1081 )
1082 return gr.scalar()
1082 return gr.scalar()
1083
1083
1084 @property
1084 @property
1085 def parents(self):
1085 def parents(self):
1086 parents_recursion_limit = 5
1086 parents_recursion_limit = 5
1087 groups = []
1087 groups = []
1088 if self.parent_group is None:
1088 if self.parent_group is None:
1089 return groups
1089 return groups
1090 cur_gr = self.parent_group
1090 cur_gr = self.parent_group
1091 groups.insert(0, cur_gr)
1091 groups.insert(0, cur_gr)
1092 cnt = 0
1092 cnt = 0
1093 while 1:
1093 while 1:
1094 cnt += 1
1094 cnt += 1
1095 gr = getattr(cur_gr, 'parent_group', None)
1095 gr = getattr(cur_gr, 'parent_group', None)
1096 cur_gr = cur_gr.parent_group
1096 cur_gr = cur_gr.parent_group
1097 if gr is None:
1097 if gr is None:
1098 break
1098 break
1099 if cnt == parents_recursion_limit:
1099 if cnt == parents_recursion_limit:
1100 # this will prevent accidental infinit loops
1100 # this will prevent accidental infinit loops
1101 log.error('group nested more than %s' %
1101 log.error('group nested more than %s' %
1102 parents_recursion_limit)
1102 parents_recursion_limit)
1103 break
1103 break
1104
1104
1105 groups.insert(0, gr)
1105 groups.insert(0, gr)
1106 return groups
1106 return groups
1107
1107
1108 @property
1108 @property
1109 def children(self):
1109 def children(self):
1110 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1110 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1111
1111
1112 @property
1112 @property
1113 def name(self):
1113 def name(self):
1114 return self.group_name.split(RepoGroup.url_sep())[-1]
1114 return self.group_name.split(RepoGroup.url_sep())[-1]
1115
1115
1116 @property
1116 @property
1117 def full_path(self):
1117 def full_path(self):
1118 return self.group_name
1118 return self.group_name
1119
1119
1120 @property
1120 @property
1121 def full_path_splitted(self):
1121 def full_path_splitted(self):
1122 return self.group_name.split(RepoGroup.url_sep())
1122 return self.group_name.split(RepoGroup.url_sep())
1123
1123
1124 @property
1124 @property
1125 def repositories(self):
1125 def repositories(self):
1126 return Repository.query()\
1126 return Repository.query()\
1127 .filter(Repository.group == self)\
1127 .filter(Repository.group == self)\
1128 .order_by(Repository.repo_name)
1128 .order_by(Repository.repo_name)
1129
1129
1130 @property
1130 @property
1131 def repositories_recursive_count(self):
1131 def repositories_recursive_count(self):
1132 cnt = self.repositories.count()
1132 cnt = self.repositories.count()
1133
1133
1134 def children_count(group):
1134 def children_count(group):
1135 cnt = 0
1135 cnt = 0
1136 for child in group.children:
1136 for child in group.children:
1137 cnt += child.repositories.count()
1137 cnt += child.repositories.count()
1138 cnt += children_count(child)
1138 cnt += children_count(child)
1139 return cnt
1139 return cnt
1140
1140
1141 return cnt + children_count(self)
1141 return cnt + children_count(self)
1142
1142
1143 def recursive_groups_and_repos(self):
1143 def recursive_groups_and_repos(self):
1144 """
1144 """
1145 Recursive return all groups, with repositories in those groups
1145 Recursive return all groups, with repositories in those groups
1146 """
1146 """
1147 all_ = []
1147 all_ = []
1148
1148
1149 def _get_members(root_gr):
1149 def _get_members(root_gr):
1150 for r in root_gr.repositories:
1150 for r in root_gr.repositories:
1151 all_.append(r)
1151 all_.append(r)
1152 childs = root_gr.children.all()
1152 childs = root_gr.children.all()
1153 if childs:
1153 if childs:
1154 for gr in childs:
1154 for gr in childs:
1155 all_.append(gr)
1155 all_.append(gr)
1156 _get_members(gr)
1156 _get_members(gr)
1157
1157
1158 _get_members(self)
1158 _get_members(self)
1159 return [self] + all_
1159 return [self] + all_
1160
1160
1161 def get_new_name(self, group_name):
1161 def get_new_name(self, group_name):
1162 """
1162 """
1163 returns new full group name based on parent and new name
1163 returns new full group name based on parent and new name
1164
1164
1165 :param group_name:
1165 :param group_name:
1166 """
1166 """
1167 path_prefix = (self.parent_group.full_path_splitted if
1167 path_prefix = (self.parent_group.full_path_splitted if
1168 self.parent_group else [])
1168 self.parent_group else [])
1169 return RepoGroup.url_sep().join(path_prefix + [group_name])
1169 return RepoGroup.url_sep().join(path_prefix + [group_name])
1170
1170
1171
1171
1172 class Permission(Base, BaseModel):
1172 class Permission(Base, BaseModel):
1173 __tablename__ = 'permissions'
1173 __tablename__ = 'permissions'
1174 __table_args__ = (
1174 __table_args__ = (
1175 Index('p_perm_name_idx', 'permission_name'),
1175 Index('p_perm_name_idx', 'permission_name'),
1176 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1176 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1177 'mysql_charset': 'utf8'},
1177 'mysql_charset': 'utf8'},
1178 )
1178 )
1179 PERMS = [
1179 PERMS = [
1180 ('repository.none', _('Repository no access')),
1180 ('repository.none', _('Repository no access')),
1181 ('repository.read', _('Repository read access')),
1181 ('repository.read', _('Repository read access')),
1182 ('repository.write', _('Repository write access')),
1182 ('repository.write', _('Repository write access')),
1183 ('repository.admin', _('Repository admin access')),
1183 ('repository.admin', _('Repository admin access')),
1184
1184
1185 ('group.none', _('Repositories Group no access')),
1185 ('group.none', _('Repositories Group no access')),
1186 ('group.read', _('Repositories Group read access')),
1186 ('group.read', _('Repositories Group read access')),
1187 ('group.write', _('Repositories Group write access')),
1187 ('group.write', _('Repositories Group write access')),
1188 ('group.admin', _('Repositories Group admin access')),
1188 ('group.admin', _('Repositories Group admin access')),
1189
1189
1190 ('hg.admin', _('RhodeCode Administrator')),
1190 ('hg.admin', _('RhodeCode Administrator')),
1191 ('hg.create.none', _('Repository creation disabled')),
1191 ('hg.create.none', _('Repository creation disabled')),
1192 ('hg.create.repository', _('Repository creation enabled')),
1192 ('hg.create.repository', _('Repository creation enabled')),
1193 ('hg.fork.none', _('Repository forking disabled')),
1193 ('hg.fork.none', _('Repository forking disabled')),
1194 ('hg.fork.repository', _('Repository forking enabled')),
1194 ('hg.fork.repository', _('Repository forking enabled')),
1195 ('hg.register.none', _('Register disabled')),
1195 ('hg.register.none', _('Register disabled')),
1196 ('hg.register.manual_activate', _('Register new user with RhodeCode '
1196 ('hg.register.manual_activate', _('Register new user with RhodeCode '
1197 'with manual activation')),
1197 'with manual activation')),
1198
1198
1199 ('hg.register.auto_activate', _('Register new user with RhodeCode '
1199 ('hg.register.auto_activate', _('Register new user with RhodeCode '
1200 'with auto activation')),
1200 'with auto activation')),
1201 ]
1201 ]
1202
1202
1203 # defines which permissions are more important higher the more important
1203 # defines which permissions are more important higher the more important
1204 PERM_WEIGHTS = {
1204 PERM_WEIGHTS = {
1205 'repository.none': 0,
1205 'repository.none': 0,
1206 'repository.read': 1,
1206 'repository.read': 1,
1207 'repository.write': 3,
1207 'repository.write': 3,
1208 'repository.admin': 4,
1208 'repository.admin': 4,
1209
1209
1210 'group.none': 0,
1210 'group.none': 0,
1211 'group.read': 1,
1211 'group.read': 1,
1212 'group.write': 3,
1212 'group.write': 3,
1213 'group.admin': 4,
1213 'group.admin': 4,
1214
1214
1215 'hg.fork.none': 0,
1215 'hg.fork.none': 0,
1216 'hg.fork.repository': 1,
1216 'hg.fork.repository': 1,
1217 'hg.create.none': 0,
1217 'hg.create.none': 0,
1218 'hg.create.repository':1
1218 'hg.create.repository':1
1219 }
1219 }
1220
1220
1221 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1221 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1222 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1222 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1223 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1223 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1224
1224
1225 def __unicode__(self):
1225 def __unicode__(self):
1226 return u"<%s('%s:%s')>" % (
1226 return u"<%s('%s:%s')>" % (
1227 self.__class__.__name__, self.permission_id, self.permission_name
1227 self.__class__.__name__, self.permission_id, self.permission_name
1228 )
1228 )
1229
1229
1230 @classmethod
1230 @classmethod
1231 def get_by_key(cls, key):
1231 def get_by_key(cls, key):
1232 return cls.query().filter(cls.permission_name == key).scalar()
1232 return cls.query().filter(cls.permission_name == key).scalar()
1233
1233
1234 @classmethod
1234 @classmethod
1235 def get_default_perms(cls, default_user_id):
1235 def get_default_perms(cls, default_user_id):
1236 q = Session().query(UserRepoToPerm, Repository, cls)\
1236 q = Session().query(UserRepoToPerm, Repository, cls)\
1237 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1237 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1238 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1238 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1239 .filter(UserRepoToPerm.user_id == default_user_id)
1239 .filter(UserRepoToPerm.user_id == default_user_id)
1240
1240
1241 return q.all()
1241 return q.all()
1242
1242
1243 @classmethod
1243 @classmethod
1244 def get_default_group_perms(cls, default_user_id):
1244 def get_default_group_perms(cls, default_user_id):
1245 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1245 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1246 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1246 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1247 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1247 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1248 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1248 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1249
1249
1250 return q.all()
1250 return q.all()
1251
1251
1252
1252
1253 class UserRepoToPerm(Base, BaseModel):
1253 class UserRepoToPerm(Base, BaseModel):
1254 __tablename__ = 'repo_to_perm'
1254 __tablename__ = 'repo_to_perm'
1255 __table_args__ = (
1255 __table_args__ = (
1256 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1256 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1257 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1257 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1258 'mysql_charset': 'utf8'}
1258 'mysql_charset': 'utf8'}
1259 )
1259 )
1260 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1260 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1261 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1261 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1262 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1262 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1263 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1263 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1264
1264
1265 user = relationship('User')
1265 user = relationship('User')
1266 repository = relationship('Repository')
1266 repository = relationship('Repository')
1267 permission = relationship('Permission')
1267 permission = relationship('Permission')
1268
1268
1269 @classmethod
1269 @classmethod
1270 def create(cls, user, repository, permission):
1270 def create(cls, user, repository, permission):
1271 n = cls()
1271 n = cls()
1272 n.user = user
1272 n.user = user
1273 n.repository = repository
1273 n.repository = repository
1274 n.permission = permission
1274 n.permission = permission
1275 Session().add(n)
1275 Session().add(n)
1276 return n
1276 return n
1277
1277
1278 def __unicode__(self):
1278 def __unicode__(self):
1279 return u'<user:%s => %s >' % (self.user, self.repository)
1279 return u'<user:%s => %s >' % (self.user, self.repository)
1280
1280
1281
1281
1282 class UserToPerm(Base, BaseModel):
1282 class UserToPerm(Base, BaseModel):
1283 __tablename__ = 'user_to_perm'
1283 __tablename__ = 'user_to_perm'
1284 __table_args__ = (
1284 __table_args__ = (
1285 UniqueConstraint('user_id', 'permission_id'),
1285 UniqueConstraint('user_id', 'permission_id'),
1286 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1286 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1287 'mysql_charset': 'utf8'}
1287 'mysql_charset': 'utf8'}
1288 )
1288 )
1289 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1289 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1290 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1290 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1291 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1291 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1292
1292
1293 user = relationship('User')
1293 user = relationship('User')
1294 permission = relationship('Permission', lazy='joined')
1294 permission = relationship('Permission', lazy='joined')
1295
1295
1296
1296
1297 class UsersGroupRepoToPerm(Base, BaseModel):
1297 class UsersGroupRepoToPerm(Base, BaseModel):
1298 __tablename__ = 'users_group_repo_to_perm'
1298 __tablename__ = 'users_group_repo_to_perm'
1299 __table_args__ = (
1299 __table_args__ = (
1300 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1300 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1301 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1301 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1302 'mysql_charset': 'utf8'}
1302 'mysql_charset': 'utf8'}
1303 )
1303 )
1304 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1304 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1305 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1305 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1306 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1306 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1307 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1307 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1308
1308
1309 users_group = relationship('UsersGroup')
1309 users_group = relationship('UsersGroup')
1310 permission = relationship('Permission')
1310 permission = relationship('Permission')
1311 repository = relationship('Repository')
1311 repository = relationship('Repository')
1312
1312
1313 @classmethod
1313 @classmethod
1314 def create(cls, users_group, repository, permission):
1314 def create(cls, users_group, repository, permission):
1315 n = cls()
1315 n = cls()
1316 n.users_group = users_group
1316 n.users_group = users_group
1317 n.repository = repository
1317 n.repository = repository
1318 n.permission = permission
1318 n.permission = permission
1319 Session().add(n)
1319 Session().add(n)
1320 return n
1320 return n
1321
1321
1322 def __unicode__(self):
1322 def __unicode__(self):
1323 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
1323 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
1324
1324
1325
1325
1326 class UsersGroupToPerm(Base, BaseModel):
1326 class UsersGroupToPerm(Base, BaseModel):
1327 __tablename__ = 'users_group_to_perm'
1327 __tablename__ = 'users_group_to_perm'
1328 __table_args__ = (
1328 __table_args__ = (
1329 UniqueConstraint('users_group_id', 'permission_id',),
1329 UniqueConstraint('users_group_id', 'permission_id',),
1330 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1330 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1331 'mysql_charset': 'utf8'}
1331 'mysql_charset': 'utf8'}
1332 )
1332 )
1333 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1333 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1334 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1334 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1335 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1335 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1336
1336
1337 users_group = relationship('UsersGroup')
1337 users_group = relationship('UsersGroup')
1338 permission = relationship('Permission')
1338 permission = relationship('Permission')
1339
1339
1340
1340
1341 class UserRepoGroupToPerm(Base, BaseModel):
1341 class UserRepoGroupToPerm(Base, BaseModel):
1342 __tablename__ = 'user_repo_group_to_perm'
1342 __tablename__ = 'user_repo_group_to_perm'
1343 __table_args__ = (
1343 __table_args__ = (
1344 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1344 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1345 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1345 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1346 'mysql_charset': 'utf8'}
1346 'mysql_charset': 'utf8'}
1347 )
1347 )
1348
1348
1349 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1349 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1350 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1350 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1351 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1351 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1352 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1352 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1353
1353
1354 user = relationship('User')
1354 user = relationship('User')
1355 group = relationship('RepoGroup')
1355 group = relationship('RepoGroup')
1356 permission = relationship('Permission')
1356 permission = relationship('Permission')
1357
1357
1358
1358
1359 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1359 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1360 __tablename__ = 'users_group_repo_group_to_perm'
1360 __tablename__ = 'users_group_repo_group_to_perm'
1361 __table_args__ = (
1361 __table_args__ = (
1362 UniqueConstraint('users_group_id', 'group_id'),
1362 UniqueConstraint('users_group_id', 'group_id'),
1363 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1363 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1364 'mysql_charset': 'utf8'}
1364 'mysql_charset': 'utf8'}
1365 )
1365 )
1366
1366
1367 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1367 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1368 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1368 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1369 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1369 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1370 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1370 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1371
1371
1372 users_group = relationship('UsersGroup')
1372 users_group = relationship('UsersGroup')
1373 permission = relationship('Permission')
1373 permission = relationship('Permission')
1374 group = relationship('RepoGroup')
1374 group = relationship('RepoGroup')
1375
1375
1376
1376
1377 class Statistics(Base, BaseModel):
1377 class Statistics(Base, BaseModel):
1378 __tablename__ = 'statistics'
1378 __tablename__ = 'statistics'
1379 __table_args__ = (
1379 __table_args__ = (
1380 UniqueConstraint('repository_id'),
1380 UniqueConstraint('repository_id'),
1381 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1381 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1382 'mysql_charset': 'utf8'}
1382 'mysql_charset': 'utf8'}
1383 )
1383 )
1384 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1384 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1385 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1385 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1386 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1386 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1387 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1387 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1388 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1388 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1389 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1389 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1390
1390
1391 repository = relationship('Repository', single_parent=True)
1391 repository = relationship('Repository', single_parent=True)
1392
1392
1393
1393
1394 class UserFollowing(Base, BaseModel):
1394 class UserFollowing(Base, BaseModel):
1395 __tablename__ = 'user_followings'
1395 __tablename__ = 'user_followings'
1396 __table_args__ = (
1396 __table_args__ = (
1397 UniqueConstraint('user_id', 'follows_repository_id'),
1397 UniqueConstraint('user_id', 'follows_repository_id'),
1398 UniqueConstraint('user_id', 'follows_user_id'),
1398 UniqueConstraint('user_id', 'follows_user_id'),
1399 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1399 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1400 'mysql_charset': 'utf8'}
1400 'mysql_charset': 'utf8'}
1401 )
1401 )
1402
1402
1403 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1403 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1404 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1404 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1405 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1405 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1406 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1406 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1407 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1407 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1408
1408
1409 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1409 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1410
1410
1411 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1411 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1412 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1412 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1413
1413
1414 @classmethod
1414 @classmethod
1415 def get_repo_followers(cls, repo_id):
1415 def get_repo_followers(cls, repo_id):
1416 return cls.query().filter(cls.follows_repo_id == repo_id)
1416 return cls.query().filter(cls.follows_repo_id == repo_id)
1417
1417
1418
1418
1419 class CacheInvalidation(Base, BaseModel):
1419 class CacheInvalidation(Base, BaseModel):
1420 __tablename__ = 'cache_invalidation'
1420 __tablename__ = 'cache_invalidation'
1421 __table_args__ = (
1421 __table_args__ = (
1422 UniqueConstraint('cache_key'),
1422 UniqueConstraint('cache_key'),
1423 Index('key_idx', 'cache_key'),
1423 Index('key_idx', 'cache_key'),
1424 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1424 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1425 'mysql_charset': 'utf8'},
1425 'mysql_charset': 'utf8'},
1426 )
1426 )
1427 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1427 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1428 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1428 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1429 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1429 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1430 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1430 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1431
1431
1432 def __init__(self, cache_key, cache_args=''):
1432 def __init__(self, cache_key, cache_args=''):
1433 self.cache_key = cache_key
1433 self.cache_key = cache_key
1434 self.cache_args = cache_args
1434 self.cache_args = cache_args
1435 self.cache_active = False
1435 self.cache_active = False
1436
1436
1437 def __unicode__(self):
1437 def __unicode__(self):
1438 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1438 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1439 self.cache_id, self.cache_key)
1439 self.cache_id, self.cache_key)
1440
1440
1441 @property
1441 @property
1442 def prefix(self):
1442 def prefix(self):
1443 _split = self.cache_key.split(self.cache_args, 1)
1443 _split = self.cache_key.split(self.cache_args, 1)
1444 if _split and len(_split) == 2:
1444 if _split and len(_split) == 2:
1445 return _split[0]
1445 return _split[0]
1446 return ''
1446 return ''
1447
1447
1448 @classmethod
1448 @classmethod
1449 def clear_cache(cls):
1449 def clear_cache(cls):
1450 cls.query().delete()
1450 cls.query().delete()
1451
1451
1452 @classmethod
1452 @classmethod
1453 def _get_key(cls, key):
1453 def _get_key(cls, key):
1454 """
1454 """
1455 Wrapper for generating a key, together with a prefix
1455 Wrapper for generating a key, together with a prefix
1456
1456
1457 :param key:
1457 :param key:
1458 """
1458 """
1459 import rhodecode
1459 import rhodecode
1460 prefix = ''
1460 prefix = ''
1461 org_key = key
1461 org_key = key
1462 iid = rhodecode.CONFIG.get('instance_id')
1462 iid = rhodecode.CONFIG.get('instance_id')
1463 if iid:
1463 if iid:
1464 prefix = iid
1464 prefix = iid
1465
1465
1466 return "%s%s" % (prefix, key), prefix, org_key
1466 return "%s%s" % (prefix, key), prefix, org_key
1467
1467
1468 @classmethod
1468 @classmethod
1469 def get_by_key(cls, key):
1469 def get_by_key(cls, key):
1470 return cls.query().filter(cls.cache_key == key).scalar()
1470 return cls.query().filter(cls.cache_key == key).scalar()
1471
1471
1472 @classmethod
1472 @classmethod
1473 def get_by_repo_name(cls, repo_name):
1473 def get_by_repo_name(cls, repo_name):
1474 return cls.query().filter(cls.cache_args == repo_name).all()
1474 return cls.query().filter(cls.cache_args == repo_name).all()
1475
1475
1476 @classmethod
1476 @classmethod
1477 def _get_or_create_key(cls, key, repo_name, commit=True):
1477 def _get_or_create_key(cls, key, repo_name, commit=True):
1478 inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar()
1478 inv_obj = Session().query(cls).filter(cls.cache_key == key).scalar()
1479 if not inv_obj:
1479 if not inv_obj:
1480 try:
1480 try:
1481 inv_obj = CacheInvalidation(key, repo_name)
1481 inv_obj = CacheInvalidation(key, repo_name)
1482 Session().add(inv_obj)
1482 Session().add(inv_obj)
1483 if commit:
1483 if commit:
1484 Session().commit()
1484 Session().commit()
1485 except Exception:
1485 except Exception:
1486 log.error(traceback.format_exc())
1486 log.error(traceback.format_exc())
1487 Session().rollback()
1487 Session().rollback()
1488 return inv_obj
1488 return inv_obj
1489
1489
1490 @classmethod
1490 @classmethod
1491 def invalidate(cls, key):
1491 def invalidate(cls, key):
1492 """
1492 """
1493 Returns Invalidation object if this given key should be invalidated
1493 Returns Invalidation object if this given key should be invalidated
1494 None otherwise. `cache_active = False` means that this cache
1494 None otherwise. `cache_active = False` means that this cache
1495 state is not valid and needs to be invalidated
1495 state is not valid and needs to be invalidated
1496
1496
1497 :param key:
1497 :param key:
1498 """
1498 """
1499 repo_name = key
1499 repo_name = key
1500 repo_name = remove_suffix(repo_name, '_README')
1500 repo_name = remove_suffix(repo_name, '_README')
1501 repo_name = remove_suffix(repo_name, '_RSS')
1501 repo_name = remove_suffix(repo_name, '_RSS')
1502 repo_name = remove_suffix(repo_name, '_ATOM')
1502 repo_name = remove_suffix(repo_name, '_ATOM')
1503
1503
1504 # adds instance prefix
1504 # adds instance prefix
1505 key, _prefix, _org_key = cls._get_key(key)
1505 key, _prefix, _org_key = cls._get_key(key)
1506 inv = cls._get_or_create_key(key, repo_name)
1506 inv = cls._get_or_create_key(key, repo_name)
1507
1507
1508 if inv and inv.cache_active is False:
1508 if inv and inv.cache_active is False:
1509 return inv
1509 return inv
1510
1510
1511 @classmethod
1511 @classmethod
1512 def set_invalidate(cls, key=None, repo_name=None):
1512 def set_invalidate(cls, key=None, repo_name=None):
1513 """
1513 """
1514 Mark this Cache key for invalidation, either by key or whole
1514 Mark this Cache key for invalidation, either by key or whole
1515 cache sets based on repo_name
1515 cache sets based on repo_name
1516
1516
1517 :param key:
1517 :param key:
1518 """
1518 """
1519 if key:
1519 if key:
1520 key, _prefix, _org_key = cls._get_key(key)
1520 key, _prefix, _org_key = cls._get_key(key)
1521 inv_objs = Session().query(cls).filter(cls.cache_key == key).all()
1521 inv_objs = Session().query(cls).filter(cls.cache_key == key).all()
1522 elif repo_name:
1522 elif repo_name:
1523 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1523 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1524
1524
1525 log.debug('marking %s key[s] for invalidation based on key=%s,repo_name=%s'
1525 log.debug('marking %s key[s] for invalidation based on key=%s,repo_name=%s'
1526 % (len(inv_objs), key, repo_name))
1526 % (len(inv_objs), key, repo_name))
1527 try:
1527 try:
1528 for inv_obj in inv_objs:
1528 for inv_obj in inv_objs:
1529 inv_obj.cache_active = False
1529 inv_obj.cache_active = False
1530 Session().add(inv_obj)
1530 Session().add(inv_obj)
1531 Session().commit()
1531 Session().commit()
1532 except Exception:
1532 except Exception:
1533 log.error(traceback.format_exc())
1533 log.error(traceback.format_exc())
1534 Session().rollback()
1534 Session().rollback()
1535
1535
1536 @classmethod
1536 @classmethod
1537 def set_valid(cls, key):
1537 def set_valid(cls, key):
1538 """
1538 """
1539 Mark this cache key as active and currently cached
1539 Mark this cache key as active and currently cached
1540
1540
1541 :param key:
1541 :param key:
1542 """
1542 """
1543 inv_obj = cls.get_by_key(key)
1543 inv_obj = cls.get_by_key(key)
1544 inv_obj.cache_active = True
1544 inv_obj.cache_active = True
1545 Session().add(inv_obj)
1545 Session().add(inv_obj)
1546 Session().commit()
1546 Session().commit()
1547
1547
1548 @classmethod
1548 @classmethod
1549 def get_cache_map(cls):
1549 def get_cache_map(cls):
1550
1550
1551 class cachemapdict(dict):
1551 class cachemapdict(dict):
1552
1552
1553 def __init__(self, *args, **kwargs):
1553 def __init__(self, *args, **kwargs):
1554 fixkey = kwargs.get('fixkey')
1554 fixkey = kwargs.get('fixkey')
1555 if fixkey:
1555 if fixkey:
1556 del kwargs['fixkey']
1556 del kwargs['fixkey']
1557 self.fixkey = fixkey
1557 self.fixkey = fixkey
1558 super(cachemapdict, self).__init__(*args, **kwargs)
1558 super(cachemapdict, self).__init__(*args, **kwargs)
1559
1559
1560 def __getattr__(self, name):
1560 def __getattr__(self, name):
1561 key = name
1561 key = name
1562 if self.fixkey:
1562 if self.fixkey:
1563 key, _prefix, _org_key = cls._get_key(key)
1563 key, _prefix, _org_key = cls._get_key(key)
1564 if key in self.__dict__:
1564 if key in self.__dict__:
1565 return self.__dict__[key]
1565 return self.__dict__[key]
1566 else:
1566 else:
1567 return self[key]
1567 return self[key]
1568
1568
1569 def __getitem__(self, key):
1569 def __getitem__(self, key):
1570 if self.fixkey:
1570 if self.fixkey:
1571 key, _prefix, _org_key = cls._get_key(key)
1571 key, _prefix, _org_key = cls._get_key(key)
1572 try:
1572 try:
1573 return super(cachemapdict, self).__getitem__(key)
1573 return super(cachemapdict, self).__getitem__(key)
1574 except KeyError:
1574 except KeyError:
1575 return
1575 return
1576
1576
1577 cache_map = cachemapdict(fixkey=True)
1577 cache_map = cachemapdict(fixkey=True)
1578 for obj in cls.query().all():
1578 for obj in cls.query().all():
1579 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1579 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1580 return cache_map
1580 return cache_map
1581
1581
1582
1582
1583 class ChangesetComment(Base, BaseModel):
1583 class ChangesetComment(Base, BaseModel):
1584 __tablename__ = 'changeset_comments'
1584 __tablename__ = 'changeset_comments'
1585 __table_args__ = (
1585 __table_args__ = (
1586 Index('cc_revision_idx', 'revision'),
1586 Index('cc_revision_idx', 'revision'),
1587 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1587 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1588 'mysql_charset': 'utf8'},
1588 'mysql_charset': 'utf8'},
1589 )
1589 )
1590 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1590 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1591 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1591 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1592 revision = Column('revision', String(40), nullable=True)
1592 revision = Column('revision', String(40), nullable=True)
1593 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1593 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1594 line_no = Column('line_no', Unicode(10), nullable=True)
1594 line_no = Column('line_no', Unicode(10), nullable=True)
1595 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1595 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1596 f_path = Column('f_path', Unicode(1000), nullable=True)
1596 f_path = Column('f_path', Unicode(1000), nullable=True)
1597 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1597 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1598 text = Column('text', UnicodeText(25000), nullable=False)
1598 text = Column('text', UnicodeText(25000), nullable=False)
1599 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1599 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1600 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1600 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1601
1601
1602 author = relationship('User', lazy='joined')
1602 author = relationship('User', lazy='joined')
1603 repo = relationship('Repository')
1603 repo = relationship('Repository')
1604 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1604 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1605 pull_request = relationship('PullRequest', lazy='joined')
1605 pull_request = relationship('PullRequest', lazy='joined')
1606
1606
1607 @classmethod
1607 @classmethod
1608 def get_users(cls, revision=None, pull_request_id=None):
1608 def get_users(cls, revision=None, pull_request_id=None):
1609 """
1609 """
1610 Returns user associated with this ChangesetComment. ie those
1610 Returns user associated with this ChangesetComment. ie those
1611 who actually commented
1611 who actually commented
1612
1612
1613 :param cls:
1613 :param cls:
1614 :param revision:
1614 :param revision:
1615 """
1615 """
1616 q = Session().query(User)\
1616 q = Session().query(User)\
1617 .join(ChangesetComment.author)
1617 .join(ChangesetComment.author)
1618 if revision:
1618 if revision:
1619 q = q.filter(cls.revision == revision)
1619 q = q.filter(cls.revision == revision)
1620 elif pull_request_id:
1620 elif pull_request_id:
1621 q = q.filter(cls.pull_request_id == pull_request_id)
1621 q = q.filter(cls.pull_request_id == pull_request_id)
1622 return q.all()
1622 return q.all()
1623
1623
1624
1624
1625 class ChangesetStatus(Base, BaseModel):
1625 class ChangesetStatus(Base, BaseModel):
1626 __tablename__ = 'changeset_statuses'
1626 __tablename__ = 'changeset_statuses'
1627 __table_args__ = (
1627 __table_args__ = (
1628 Index('cs_revision_idx', 'revision'),
1628 Index('cs_revision_idx', 'revision'),
1629 Index('cs_version_idx', 'version'),
1629 Index('cs_version_idx', 'version'),
1630 UniqueConstraint('repo_id', 'revision', 'version'),
1630 UniqueConstraint('repo_id', 'revision', 'version'),
1631 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1631 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1632 'mysql_charset': 'utf8'}
1632 'mysql_charset': 'utf8'}
1633 )
1633 )
1634 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1634 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1635 STATUS_APPROVED = 'approved'
1635 STATUS_APPROVED = 'approved'
1636 STATUS_REJECTED = 'rejected'
1636 STATUS_REJECTED = 'rejected'
1637 STATUS_UNDER_REVIEW = 'under_review'
1637 STATUS_UNDER_REVIEW = 'under_review'
1638
1638
1639 STATUSES = [
1639 STATUSES = [
1640 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1640 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1641 (STATUS_APPROVED, _("Approved")),
1641 (STATUS_APPROVED, _("Approved")),
1642 (STATUS_REJECTED, _("Rejected")),
1642 (STATUS_REJECTED, _("Rejected")),
1643 (STATUS_UNDER_REVIEW, _("Under Review")),
1643 (STATUS_UNDER_REVIEW, _("Under Review")),
1644 ]
1644 ]
1645
1645
1646 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1646 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1647 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1647 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1648 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1648 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1649 revision = Column('revision', String(40), nullable=False)
1649 revision = Column('revision', String(40), nullable=False)
1650 status = Column('status', String(128), nullable=False, default=DEFAULT)
1650 status = Column('status', String(128), nullable=False, default=DEFAULT)
1651 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1651 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1652 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1652 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1653 version = Column('version', Integer(), nullable=False, default=0)
1653 version = Column('version', Integer(), nullable=False, default=0)
1654 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1654 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1655
1655
1656 author = relationship('User', lazy='joined')
1656 author = relationship('User', lazy='joined')
1657 repo = relationship('Repository')
1657 repo = relationship('Repository')
1658 comment = relationship('ChangesetComment', lazy='joined')
1658 comment = relationship('ChangesetComment', lazy='joined')
1659 pull_request = relationship('PullRequest', lazy='joined')
1659 pull_request = relationship('PullRequest', lazy='joined')
1660
1660
1661 def __unicode__(self):
1661 def __unicode__(self):
1662 return u"<%s('%s:%s')>" % (
1662 return u"<%s('%s:%s')>" % (
1663 self.__class__.__name__,
1663 self.__class__.__name__,
1664 self.status, self.author
1664 self.status, self.author
1665 )
1665 )
1666
1666
1667 @classmethod
1667 @classmethod
1668 def get_status_lbl(cls, value):
1668 def get_status_lbl(cls, value):
1669 return dict(cls.STATUSES).get(value)
1669 return dict(cls.STATUSES).get(value)
1670
1670
1671 @property
1671 @property
1672 def status_lbl(self):
1672 def status_lbl(self):
1673 return ChangesetStatus.get_status_lbl(self.status)
1673 return ChangesetStatus.get_status_lbl(self.status)
1674
1674
1675
1675
1676 class PullRequest(Base, BaseModel):
1676 class PullRequest(Base, BaseModel):
1677 __tablename__ = 'pull_requests'
1677 __tablename__ = 'pull_requests'
1678 __table_args__ = (
1678 __table_args__ = (
1679 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1679 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1680 'mysql_charset': 'utf8'},
1680 'mysql_charset': 'utf8'},
1681 )
1681 )
1682
1682
1683 STATUS_NEW = u'new'
1683 STATUS_NEW = u'new'
1684 STATUS_OPEN = u'open'
1684 STATUS_OPEN = u'open'
1685 STATUS_CLOSED = u'closed'
1685 STATUS_CLOSED = u'closed'
1686
1686
1687 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1687 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1688 title = Column('title', Unicode(256), nullable=True)
1688 title = Column('title', Unicode(256), nullable=True)
1689 description = Column('description', UnicodeText(10240), nullable=True)
1689 description = Column('description', UnicodeText(10240), nullable=True)
1690 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1690 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1691 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1691 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1692 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1692 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1693 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1693 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1694 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1694 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1695 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1695 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1696 org_ref = Column('org_ref', Unicode(256), nullable=False)
1696 org_ref = Column('org_ref', Unicode(256), nullable=False)
1697 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1697 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1698 other_ref = Column('other_ref', Unicode(256), nullable=False)
1698 other_ref = Column('other_ref', Unicode(256), nullable=False)
1699
1699
1700 @hybrid_property
1700 @hybrid_property
1701 def revisions(self):
1701 def revisions(self):
1702 return self._revisions.split(':')
1702 return self._revisions.split(':')
1703
1703
1704 @revisions.setter
1704 @revisions.setter
1705 def revisions(self, val):
1705 def revisions(self, val):
1706 self._revisions = ':'.join(val)
1706 self._revisions = ':'.join(val)
1707
1707
1708 author = relationship('User', lazy='joined')
1708 author = relationship('User', lazy='joined')
1709 reviewers = relationship('PullRequestReviewers',
1709 reviewers = relationship('PullRequestReviewers',
1710 cascade="all, delete, delete-orphan")
1710 cascade="all, delete, delete-orphan")
1711 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1711 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
1712 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1712 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
1713 statuses = relationship('ChangesetStatus')
1713 statuses = relationship('ChangesetStatus')
1714 comments = relationship('ChangesetComment',
1714 comments = relationship('ChangesetComment',
1715 cascade="all, delete, delete-orphan")
1715 cascade="all, delete, delete-orphan")
1716
1716
1717 def is_closed(self):
1717 def is_closed(self):
1718 return self.status == self.STATUS_CLOSED
1718 return self.status == self.STATUS_CLOSED
1719
1719
1720 def __json__(self):
1720 def __json__(self):
1721 return dict(
1721 return dict(
1722 revisions=self.revisions
1722 revisions=self.revisions
1723 )
1723 )
1724
1724
1725
1725
1726 class PullRequestReviewers(Base, BaseModel):
1726 class PullRequestReviewers(Base, BaseModel):
1727 __tablename__ = 'pull_request_reviewers'
1727 __tablename__ = 'pull_request_reviewers'
1728 __table_args__ = (
1728 __table_args__ = (
1729 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1729 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1730 'mysql_charset': 'utf8'},
1730 'mysql_charset': 'utf8'},
1731 )
1731 )
1732
1732
1733 def __init__(self, user=None, pull_request=None):
1733 def __init__(self, user=None, pull_request=None):
1734 self.user = user
1734 self.user = user
1735 self.pull_request = pull_request
1735 self.pull_request = pull_request
1736
1736
1737 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1737 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
1738 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1738 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
1739 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1739 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
1740
1740
1741 user = relationship('User')
1741 user = relationship('User')
1742 pull_request = relationship('PullRequest')
1742 pull_request = relationship('PullRequest')
1743
1743
1744
1744
1745 class Notification(Base, BaseModel):
1745 class Notification(Base, BaseModel):
1746 __tablename__ = 'notifications'
1746 __tablename__ = 'notifications'
1747 __table_args__ = (
1747 __table_args__ = (
1748 Index('notification_type_idx', 'type'),
1748 Index('notification_type_idx', 'type'),
1749 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1749 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1750 'mysql_charset': 'utf8'},
1750 'mysql_charset': 'utf8'},
1751 )
1751 )
1752
1752
1753 TYPE_CHANGESET_COMMENT = u'cs_comment'
1753 TYPE_CHANGESET_COMMENT = u'cs_comment'
1754 TYPE_MESSAGE = u'message'
1754 TYPE_MESSAGE = u'message'
1755 TYPE_MENTION = u'mention'
1755 TYPE_MENTION = u'mention'
1756 TYPE_REGISTRATION = u'registration'
1756 TYPE_REGISTRATION = u'registration'
1757 TYPE_PULL_REQUEST = u'pull_request'
1757 TYPE_PULL_REQUEST = u'pull_request'
1758 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1758 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
1759
1759
1760 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1760 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1761 subject = Column('subject', Unicode(512), nullable=True)
1761 subject = Column('subject', Unicode(512), nullable=True)
1762 body = Column('body', UnicodeText(50000), nullable=True)
1762 body = Column('body', UnicodeText(50000), nullable=True)
1763 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1763 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1764 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1764 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1765 type_ = Column('type', Unicode(256))
1765 type_ = Column('type', Unicode(256))
1766
1766
1767 created_by_user = relationship('User')
1767 created_by_user = relationship('User')
1768 notifications_to_users = relationship('UserNotification', lazy='joined',
1768 notifications_to_users = relationship('UserNotification', lazy='joined',
1769 cascade="all, delete, delete-orphan")
1769 cascade="all, delete, delete-orphan")
1770
1770
1771 @property
1771 @property
1772 def recipients(self):
1772 def recipients(self):
1773 return [x.user for x in UserNotification.query()\
1773 return [x.user for x in UserNotification.query()\
1774 .filter(UserNotification.notification == self)\
1774 .filter(UserNotification.notification == self)\
1775 .order_by(UserNotification.user_id.asc()).all()]
1775 .order_by(UserNotification.user_id.asc()).all()]
1776
1776
1777 @classmethod
1777 @classmethod
1778 def create(cls, created_by, subject, body, recipients, type_=None):
1778 def create(cls, created_by, subject, body, recipients, type_=None):
1779 if type_ is None:
1779 if type_ is None:
1780 type_ = Notification.TYPE_MESSAGE
1780 type_ = Notification.TYPE_MESSAGE
1781
1781
1782 notification = cls()
1782 notification = cls()
1783 notification.created_by_user = created_by
1783 notification.created_by_user = created_by
1784 notification.subject = subject
1784 notification.subject = subject
1785 notification.body = body
1785 notification.body = body
1786 notification.type_ = type_
1786 notification.type_ = type_
1787 notification.created_on = datetime.datetime.now()
1787 notification.created_on = datetime.datetime.now()
1788
1788
1789 for u in recipients:
1789 for u in recipients:
1790 assoc = UserNotification()
1790 assoc = UserNotification()
1791 assoc.notification = notification
1791 assoc.notification = notification
1792 u.notifications.append(assoc)
1792 u.notifications.append(assoc)
1793 Session().add(notification)
1793 Session().add(notification)
1794 return notification
1794 return notification
1795
1795
1796 @property
1796 @property
1797 def description(self):
1797 def description(self):
1798 from rhodecode.model.notification import NotificationModel
1798 from rhodecode.model.notification import NotificationModel
1799 return NotificationModel().make_description(self)
1799 return NotificationModel().make_description(self)
1800
1800
1801
1801
1802 class UserNotification(Base, BaseModel):
1802 class UserNotification(Base, BaseModel):
1803 __tablename__ = 'user_to_notification'
1803 __tablename__ = 'user_to_notification'
1804 __table_args__ = (
1804 __table_args__ = (
1805 UniqueConstraint('user_id', 'notification_id'),
1805 UniqueConstraint('user_id', 'notification_id'),
1806 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1806 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1807 'mysql_charset': 'utf8'}
1807 'mysql_charset': 'utf8'}
1808 )
1808 )
1809 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1809 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1810 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1810 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1811 read = Column('read', Boolean, default=False)
1811 read = Column('read', Boolean, default=False)
1812 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1812 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1813
1813
1814 user = relationship('User', lazy="joined")
1814 user = relationship('User', lazy="joined")
1815 notification = relationship('Notification', lazy="joined",
1815 notification = relationship('Notification', lazy="joined",
1816 order_by=lambda: Notification.created_on.desc(),)
1816 order_by=lambda: Notification.created_on.desc(),)
1817
1817
1818 def mark_as_read(self):
1818 def mark_as_read(self):
1819 self.read = True
1819 self.read = True
1820 Session().add(self)
1820 Session().add(self)
1821
1821
1822
1822
1823 class DbMigrateVersion(Base, BaseModel):
1823 class DbMigrateVersion(Base, BaseModel):
1824 __tablename__ = 'db_migrate_version'
1824 __tablename__ = 'db_migrate_version'
1825 __table_args__ = (
1825 __table_args__ = (
1826 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1826 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1827 'mysql_charset': 'utf8'},
1827 'mysql_charset': 'utf8'},
1828 )
1828 )
1829 repository_id = Column('repository_id', String(250), primary_key=True)
1829 repository_id = Column('repository_id', String(250), primary_key=True)
1830 repository_path = Column('repository_path', Text)
1830 repository_path = Column('repository_path', Text)
1831 version = Column('version', Integer)
1831 version = Column('version', Integer)
@@ -1,45 +1,45 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Admin journal')} - ${c.rhodecode_name}
5 ${_('Admin journal')} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 <form id="filter_form">
9 <form id="filter_form">
10 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${c.search_term or _('quick filter...')}"/>
10 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${c.search_term or _('quick filter...')}"/>
11 <input type='submit' value="${_('filter')}" class="ui-btn"/>
11 <input type='submit' value="${_('filter')}" class="ui-btn" style="padding:0px 2px 0px 2px;margin:0px"/>
12 ${_('Admin journal')}
12 ${_('Admin journal')} - ${ungettext('%s entry', '%s entries', c.users_log.item_count) % (c.users_log.item_count)}
13 </form>
13 </form>
14 ${h.end_form()}
14 ${h.end_form()}
15 </%def>
15 </%def>
16
16
17 <%def name="page_nav()">
17 <%def name="page_nav()">
18 ${self.menu('admin')}
18 ${self.menu('admin')}
19 </%def>
19 </%def>
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box">
21 <div class="box">
22 <!-- box / title -->
22 <!-- box / title -->
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 </div>
25 </div>
26 <!-- end box / title -->
26 <!-- end box / title -->
27 <div class="table">
27 <div class="table">
28 <div id="user_log">
28 <div id="user_log">
29 ${c.log_data}
29 ${c.log_data}
30 </div>
30 </div>
31 </div>
31 </div>
32 </div>
32 </div>
33
33
34 <script>
34 <script>
35 YUE.on('q_filter','click',function(){
35 YUE.on('q_filter','click',function(){
36 YUD.get('q_filter').value = '';
36 YUD.get('q_filter').value = '';
37 });
37 });
38 YUE.on('filter_form','submit',function(e){
38 YUE.on('filter_form','submit',function(e){
39 YUE.preventDefault(e)
39 YUE.preventDefault(e)
40 var val = YUD.get('q_filter').value;
40 var val = YUD.get('q_filter').value;
41 window.location = "${url.current(filter='__FILTER__')}".replace('__FILTER__',val);
41 window.location = "${url.current(filter='__FILTER__')}".replace('__FILTER__',val);
42 });
42 });
43 </script>
43 </script>
44 </%def>
44 </%def>
45
45
@@ -1,58 +1,64 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 %if c.users_log:
2 %if c.users_log:
3 <table>
3 <table>
4 <tr>
4 <tr>
5 <th class="left">${_('Username')}</th>
5 <th class="left">${_('Username')}</th>
6 <th class="left">${_('Action')}</th>
6 <th class="left">${_('Action')}</th>
7 <th class="left">${_('Repository')}</th>
7 <th class="left">${_('Repository')}</th>
8 <th class="left">${_('Date')}</th>
8 <th class="left">${_('Date')}</th>
9 <th class="left">${_('From IP')}</th>
9 <th class="left">${_('From IP')}</th>
10 </tr>
10 </tr>
11
11
12 %for cnt,l in enumerate(c.users_log):
12 %for cnt,l in enumerate(c.users_log):
13 <tr class="parity${cnt%2}">
13 <tr class="parity${cnt%2}">
14 <td>${h.link_to(l.user.username,h.url('edit_user', id=l.user.user_id))}</td>
14 <td>
15 %if l.user is not None:
16 ${h.link_to(l.user.username,h.url('edit_user', id=l.user.user_id))}
17 %else:
18 ${l.username}
19 %endif
20 </td>
15 <td>${h.action_parser(l)[0]()}
21 <td>${h.action_parser(l)[0]()}
16 <div class="journal_action_params">
22 <div class="journal_action_params">
17 ${h.literal(h.action_parser(l)[1]())}
23 ${h.literal(h.action_parser(l)[1]())}
18 </div>
24 </div>
19 </td>
25 </td>
20 <td>
26 <td>
21 %if l.repository is not None:
27 %if l.repository is not None:
22 ${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}
28 ${h.link_to(l.repository.repo_name,h.url('summary_home',repo_name=l.repository.repo_name))}
23 %else:
29 %else:
24 ${l.repository_name}
30 ${l.repository_name}
25 %endif
31 %endif
26 </td>
32 </td>
27
33
28 <td>${h.fmt_date(l.action_date)}</td>
34 <td>${h.fmt_date(l.action_date)}</td>
29 <td>${l.user_ip}</td>
35 <td>${l.user_ip}</td>
30 </tr>
36 </tr>
31 %endfor
37 %endfor
32 </table>
38 </table>
33
39
34 <script type="text/javascript">
40 <script type="text/javascript">
35 YUE.onDOMReady(function(){
41 YUE.onDOMReady(function(){
36 YUE.delegate("user_log","click",function(e, matchedEl, container){
42 YUE.delegate("user_log","click",function(e, matchedEl, container){
37 ypjax(e.target.href,"user_log",function(){
43 ypjax(e.target.href,"user_log",function(){
38 show_more_event();
44 show_more_event();
39 tooltip_activate();
45 tooltip_activate();
40 show_changeset_tooltip();
46 show_changeset_tooltip();
41 });
47 });
42 YUE.preventDefault(e);
48 YUE.preventDefault(e);
43 },'.pager_link');
49 },'.pager_link');
44
50
45 YUE.delegate("user_log","click",function(e,matchedEl,container){
51 YUE.delegate("user_log","click",function(e,matchedEl,container){
46 var el = e.target;
52 var el = e.target;
47 YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
53 YUD.setStyle(YUD.get(el.id.substring(1)),'display','');
48 YUD.setStyle(el.parentNode,'display','none');
54 YUD.setStyle(el.parentNode,'display','none');
49 },'.show_more');
55 },'.show_more');
50 });
56 });
51 </script>
57 </script>
52
58
53 <div class="pagination-wh pagination-left">
59 <div class="pagination-wh pagination-left">
54 ${c.users_log.pager('$link_previous ~2~ $link_next')}
60 ${c.users_log.pager('$link_previous ~2~ $link_next')}
55 </div>
61 </div>
56 %else:
62 %else:
57 ${_('No actions yet')}
63 ${_('No actions yet')}
58 %endif
64 %endif
@@ -1,9 +1,103 b''
1 import os
2 import csv
3 import datetime
1 from rhodecode.tests import *
4 from rhodecode.tests import *
5 from rhodecode.model.db import UserLog
6 from rhodecode.model.meta import Session
7 from rhodecode.lib.utils2 import safe_unicode
8
9 dn = os.path.dirname
10 FIXTURES = os.path.join(dn(dn(os.path.abspath(__file__))), 'fixtures')
11
2
12
3 class TestAdminController(TestController):
13 class TestAdminController(TestController):
4
14
15 @classmethod
16 def setup_class(cls):
17 UserLog.query().delete()
18 Session().commit()
19 with open(os.path.join(FIXTURES, 'journal_dump.csv')) as f:
20 for row in csv.DictReader(f):
21 ul = UserLog()
22 for k, v in row.iteritems():
23 v = safe_unicode(v)
24 if k == 'action_date':
25 v = datetime.datetime.strptime(v, '%Y-%m-%d %H:%M:%S.%f')
26 setattr(ul, k, v)
27 Session().add(ul)
28 Session().commit()
29
30 @classmethod
31 def teardown_class(cls):
32 UserLog.query().delete()
33 Session().commit()
34
5 def test_index(self):
35 def test_index(self):
6 self.log_user()
36 self.log_user()
7 response = self.app.get(url(controller='admin/admin', action='index'))
37 response = self.app.get(url(controller='admin/admin', action='index'))
8 assert 'Admin journal' in response.body, 'No proper title in dashboard'
38 response.mustcontain('Admin journal')
9 # Test response...
39
40 def test_filter_all_entries(self):
41 self.log_user()
42 response = self.app.get(url(controller='admin/admin', action='index',))
43 response.mustcontain('2034 entries')
44
45 def test_filter_journal_filter_exact_match_on_repository(self):
46 self.log_user()
47 response = self.app.get(url(controller='admin/admin', action='index',
48 filter='repository:rhodecode'))
49 response.mustcontain('3 entries')
50
51 def test_filter_journal_filter_wildcard_on_repository(self):
52 self.log_user()
53 response = self.app.get(url(controller='admin/admin', action='index',
54 filter='repository:*test*'))
55 response.mustcontain('862 entries')
56
57 def test_filter_journal_filter_prefix_on_repository(self):
58 self.log_user()
59 response = self.app.get(url(controller='admin/admin', action='index',
60 filter='repository:test*'))
61 response.mustcontain('257 entries')
62
63 def test_filter_journal_filter_prefix_on_repository_and_user(self):
64 self.log_user()
65 response = self.app.get(url(controller='admin/admin', action='index',
66 filter='repository:test* AND username:demo'))
67 response.mustcontain('130 entries')
68
69 def test_filter_journal_filter_prefix_on_repository_or_other_repo(self):
70 self.log_user()
71 response = self.app.get(url(controller='admin/admin', action='index',
72 filter='repository:test* OR repository:rhodecode'))
73 response.mustcontain('260 entries') # 257 + 3
74
75 def test_filter_journal_filter_exact_match_on_username(self):
76 self.log_user()
77 response = self.app.get(url(controller='admin/admin', action='index',
78 filter='username:demo'))
79 response.mustcontain('1087 entries')
80
81 def test_filter_journal_filter_wildcard_on_username(self):
82 self.log_user()
83 response = self.app.get(url(controller='admin/admin', action='index',
84 filter='username:*test*'))
85 response.mustcontain('100 entries')
86
87 def test_filter_journal_filter_prefix_on_username(self):
88 self.log_user()
89 response = self.app.get(url(controller='admin/admin', action='index',
90 filter='username:demo*'))
91 response.mustcontain('1101 entries')
92
93 def test_filter_journal_filter_prefix_on_user_or_other_user(self):
94 self.log_user()
95 response = self.app.get(url(controller='admin/admin', action='index',
96 filter='username:demo OR username:volcan'))
97 response.mustcontain('1095 entries') # 1087 + 8
98
99 def test_filter_journal_filter_wildcard_on_action(self):
100 self.log_user()
101 response = self.app.get(url(controller='admin/admin', action='index',
102 filter='action:*pull_request*'))
103 response.mustcontain('187 entries') No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now