Show More
@@ -3,6 +3,16 b'' | |||||
3 | Changelog |
|
3 | Changelog | |
4 | ========= |
|
4 | ========= | |
5 |
|
5 | |||
|
6 | ||||
|
7 | 1.0.1 (**2010-11-10**) | |||
|
8 | ---------------------- | |||
|
9 | ||||
|
10 | - fixed #53 python2.5 incompatible enumerate calls | |||
|
11 | - fixed #52 disable mercurial extension for web | |||
|
12 | - fixed #51 deleting repositories don't delete it's dependent objects | |||
|
13 | - small css updated | |||
|
14 | ||||
|
15 | ||||
6 | 1.0.0 (**2010-11-02**) |
|
16 | 1.0.0 (**2010-11-02**) | |
7 | ---------------------- |
|
17 | ---------------------- | |
8 |
|
18 |
@@ -5,12 +5,12 b' Installation' | |||||
5 |
|
5 | |||
6 | ``RhodeCode`` is written entirely in Python, but in order to use it's full |
|
6 | ``RhodeCode`` is written entirely in Python, but in order to use it's full | |
7 | potential there are some third-party requirements. When RhodeCode is used |
|
7 | potential there are some third-party requirements. When RhodeCode is used | |
8 | together with celery You have to install some kind of message broker, |
|
8 | together with celery_ You have to install some kind of message broker, | |
9 | recommended one is rabbitmq_ to make the async tasks work. |
|
9 | recommended one is rabbitmq_ to make the async tasks work. | |
10 |
|
10 | |||
11 | Of course RhodeCode works in sync mode also, then You don't have to install |
|
11 | Of course RhodeCode works in sync mode also, then You don't have to install | |
12 | any third party apps. Celery_ will give You large speed improvement when using |
|
12 | any third party apps. Celery_ will give You large speed improvement when using | |
13 |
many big repositories. If You plan to use it for |
|
13 | many big repositories. If You plan to use it for 5 or 10 small repositories, it | |
14 | will work just fine without celery running. |
|
14 | will work just fine without celery running. | |
15 |
|
15 | |||
16 | After You decide to Run it with celery make sure You run celeryd and |
|
16 | After You decide to Run it with celery make sure You run celeryd and | |
@@ -33,7 +33,7 b' Install from Cheese Shop' | |||||
33 |
|
33 | |||
34 | Easiest way to install ``rhodecode`` is to run:: |
|
34 | Easiest way to install ``rhodecode`` is to run:: | |
35 |
|
35 | |||
36 |
|
|
36 | easy_install rhodecode | |
37 |
|
37 | |||
38 | Or:: |
|
38 | Or:: | |
39 |
|
39 | |||
@@ -42,15 +42,16 b' Or::' | |||||
42 | If you prefer to install manually simply grab latest release from |
|
42 | If you prefer to install manually simply grab latest release from | |
43 | http://pypi.python.org/pypi/rhodecode, decompres archive and run:: |
|
43 | http://pypi.python.org/pypi/rhodecode, decompres archive and run:: | |
44 |
|
44 | |||
45 |
|
|
45 | python setup.py install | |
46 |
|
46 | |||
47 |
|
47 | |||
48 | Step by step installation example |
|
48 | Step by step installation example | |
49 | --------------------------------- |
|
49 | --------------------------------- | |
50 |
|
50 | |||
51 |
|
51 | |||
52 |
- Assuming You have installed virtualenv_ create one using. |
|
52 | - Assuming You have installed virtualenv_ create one using. | |
53 |
will make sure non of Your system libs are linked |
|
53 | The `--no-site-packages` will make sure non of Your system libs are linked | |
|
54 | with this virtualenv_ | |||
54 |
|
55 | |||
55 | :: |
|
56 | :: | |
56 |
|
57 |
@@ -40,6 +40,18 b' Setting up the application' | |||||
40 | - Default permissions on each repository is read, and owner is admin. So |
|
40 | - Default permissions on each repository is read, and owner is admin. So | |
41 | remember to update these if needed. |
|
41 | remember to update these if needed. | |
42 |
|
42 | |||
|
43 | Note | |||
|
44 | ---- | |||
|
45 | ||||
|
46 | RhodeCode when running without the celery it's running all it's task in sync | |||
|
47 | mode, for first few times when visiting summary page You can notice few | |||
|
48 | slow downs, this is due the statistics building it's cache. After all changesets | |||
|
49 | are parsed it'll take the stats from cache and run much faster. Each summary | |||
|
50 | page display parse at most 250 changesets in order to not stress the cpu, so | |||
|
51 | the full stats are going to be loaded after total_number_of_changesets/250 | |||
|
52 | summary page visits. | |||
|
53 | ||||
|
54 | ||||
43 |
|
55 | |||
44 | Setting up Whoosh |
|
56 | Setting up Whoosh | |
45 | ----------------- |
|
57 | ----------------- | |
@@ -53,9 +65,9 b' Setting up Whoosh' | |||||
53 | When using incremental mode whoosh will check last modification date of each file |
|
65 | When using incremental mode whoosh will check last modification date of each file | |
54 | and add it to reindex if newer file is available. Also indexing daemon checks |
|
66 | and add it to reindex if newer file is available. Also indexing daemon checks | |
55 | for removed files and removes them from index. Sometime You might want to rebuild |
|
67 | for removed files and removes them from index. Sometime You might want to rebuild | |
56 |
index from scrach, in admin pa |
|
68 | index from scratch, in admin panel You can check `build from scratch` flag | |
57 | and in standalone daemon You can pass `full` instead on incremental to build |
|
69 | and in standalone daemon You can pass `full` instead on incremental to build | |
58 | remove previos index and build new one. |
|
70 | remove previous index and build new one. | |
59 |
|
71 | |||
60 | Nginx virtual host example |
|
72 | Nginx virtual host example | |
61 | -------------------------- |
|
73 | -------------------------- |
@@ -24,7 +24,7 b' versioning implementation: http://semver' | |||||
24 | @author: marcink |
|
24 | @author: marcink | |
25 | """ |
|
25 | """ | |
26 |
|
26 | |||
27 |
VERSION = (1, 0, |
|
27 | VERSION = (1, 0, 1,) | |
28 |
|
28 | |||
29 | __version__ = '.'.join((str(each) for each in VERSION[:4])) |
|
29 | __version__ = '.'.join((str(each) for each in VERSION[:4])) | |
30 |
|
30 |
@@ -64,20 +64,20 b" def recursive_replace(str, replace=' '):" | |||||
64 | return str |
|
64 | return str | |
65 | else: |
|
65 | else: | |
66 | str = str.replace(replace * 2, replace) |
|
66 | str = str.replace(replace * 2, replace) | |
67 |
return recursive_replace(str, replace) |
|
67 | return recursive_replace(str, replace) | |
68 |
|
68 | |||
69 | class _ToolTip(object): |
|
69 | class _ToolTip(object): | |
70 |
|
70 | |||
71 | def __call__(self, tooltip_title, trim_at=50): |
|
71 | def __call__(self, tooltip_title, trim_at=50): | |
72 | """ |
|
72 | """ | |
73 | Special function just to wrap our text into nice formatted autowrapped |
|
73 | Special function just to wrap our text into nice formatted autowrapped | |
74 | text |
|
74 | text | |
75 | :param tooltip_title: |
|
75 | :param tooltip_title: | |
76 | """ |
|
76 | """ | |
77 |
|
77 | |||
78 | return wrap_paragraphs(escape(tooltip_title), trim_at)\ |
|
78 | return wrap_paragraphs(escape(tooltip_title), trim_at)\ | |
79 | .replace('\n', '<br/>') |
|
79 | .replace('\n', '<br/>') | |
80 |
|
80 | |||
81 | def activate(self): |
|
81 | def activate(self): | |
82 | """ |
|
82 | """ | |
83 | Adds tooltip mechanism to the given Html all tooltips have to have |
|
83 | Adds tooltip mechanism to the given Html all tooltips have to have | |
@@ -85,7 +85,7 b' class _ToolTip(object):' | |||||
85 | Then a tooltip will be generated based on that |
|
85 | Then a tooltip will be generated based on that | |
86 | All with yui js tooltip |
|
86 | All with yui js tooltip | |
87 | """ |
|
87 | """ | |
88 |
|
88 | |||
89 | js = ''' |
|
89 | js = ''' | |
90 | YAHOO.util.Event.onDOMReady(function(){ |
|
90 | YAHOO.util.Event.onDOMReady(function(){ | |
91 | function toolTipsId(){ |
|
91 | function toolTipsId(){ | |
@@ -190,25 +190,25 b' class _ToolTip(object):' | |||||
190 |
|
190 | |||
191 | }); |
|
191 | }); | |
192 | }); |
|
192 | }); | |
193 |
''' |
|
193 | ''' | |
194 | return literal(js) |
|
194 | return literal(js) | |
195 |
|
195 | |||
196 | tooltip = _ToolTip() |
|
196 | tooltip = _ToolTip() | |
197 |
|
197 | |||
198 | class _FilesBreadCrumbs(object): |
|
198 | class _FilesBreadCrumbs(object): | |
199 |
|
199 | |||
200 | def __call__(self, repo_name, rev, paths): |
|
200 | def __call__(self, repo_name, rev, paths): | |
201 | url_l = [link_to(repo_name, url('files_home', |
|
201 | url_l = [link_to(repo_name, url('files_home', | |
202 | repo_name=repo_name, |
|
202 | repo_name=repo_name, | |
203 | revision=rev, f_path=''))] |
|
203 | revision=rev, f_path=''))] | |
204 | paths_l = paths.split('/') |
|
204 | paths_l = paths.split('/') | |
205 |
|
205 | |||
206 |
for cnt, p in enumerate(paths_l |
|
206 | for cnt, p in enumerate(paths_l): | |
207 | if p != '': |
|
207 | if p != '': | |
208 | url_l.append(link_to(p, url('files_home', |
|
208 | url_l.append(link_to(p, url('files_home', | |
209 | repo_name=repo_name, |
|
209 | repo_name=repo_name, | |
210 | revision=rev, |
|
210 | revision=rev, | |
211 | f_path='/'.join(paths_l[:cnt])))) |
|
211 | f_path='/'.join(paths_l[:cnt + 1])))) | |
212 |
|
212 | |||
213 | return literal('/'.join(url_l)) |
|
213 | return literal('/'.join(url_l)) | |
214 |
|
214 | |||
@@ -219,9 +219,9 b' class CodeHtmlFormatter(HtmlFormatter):' | |||||
219 | return self._wrap_div(self._wrap_pre(self._wrap_code(source))) |
|
219 | return self._wrap_div(self._wrap_pre(self._wrap_code(source))) | |
220 |
|
220 | |||
221 | def _wrap_code(self, source): |
|
221 | def _wrap_code(self, source): | |
222 |
for cnt, it in enumerate(source |
|
222 | for cnt, it in enumerate(source): | |
223 | i, t = it |
|
223 | i, t = it | |
224 | t = '<div id="#S-%s">%s</div>' % (cnt, t) |
|
224 | t = '<div id="#S-%s">%s</div>' % (cnt + 1, t) | |
225 | yield i, t |
|
225 | yield i, t | |
226 | def pygmentize(filenode, **kwargs): |
|
226 | def pygmentize(filenode, **kwargs): | |
227 | """ |
|
227 | """ | |
@@ -236,12 +236,12 b' def pygmentize_annotation(filenode, **kw' | |||||
236 | pygmentize function for annotation |
|
236 | pygmentize function for annotation | |
237 | :param filenode: |
|
237 | :param filenode: | |
238 | """ |
|
238 | """ | |
239 |
|
239 | |||
240 | color_dict = {} |
|
240 | color_dict = {} | |
241 | def gen_color(): |
|
241 | def gen_color(): | |
242 | """generator for getting 10k of evenly distibuted colors using hsv color |
|
242 | """generator for getting 10k of evenly distibuted colors using hsv color | |
243 | and golden ratio. |
|
243 | and golden ratio. | |
244 |
""" |
|
244 | """ | |
245 | import colorsys |
|
245 | import colorsys | |
246 | n = 10000 |
|
246 | n = 10000 | |
247 | golden_ratio = 0.618033988749895 |
|
247 | golden_ratio = 0.618033988749895 | |
@@ -252,21 +252,21 b' def pygmentize_annotation(filenode, **kw' | |||||
252 | h %= 1 |
|
252 | h %= 1 | |
253 | HSV_tuple = [h, 0.95, 0.95] |
|
253 | HSV_tuple = [h, 0.95, 0.95] | |
254 | RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple) |
|
254 | RGB_tuple = colorsys.hsv_to_rgb(*HSV_tuple) | |
255 |
yield map(lambda x:str(int(x * 256)), RGB_tuple) |
|
255 | yield map(lambda x:str(int(x * 256)), RGB_tuple) | |
256 |
|
256 | |||
257 | cgenerator = gen_color() |
|
257 | cgenerator = gen_color() | |
258 |
|
258 | |||
259 | def get_color_string(cs): |
|
259 | def get_color_string(cs): | |
260 | if color_dict.has_key(cs): |
|
260 | if color_dict.has_key(cs): | |
261 | col = color_dict[cs] |
|
261 | col = color_dict[cs] | |
262 | else: |
|
262 | else: | |
263 | col = color_dict[cs] = cgenerator.next() |
|
263 | col = color_dict[cs] = cgenerator.next() | |
264 | return "color: rgb(%s)! important;" % (', '.join(col)) |
|
264 | return "color: rgb(%s)! important;" % (', '.join(col)) | |
265 |
|
265 | |||
266 | def url_func(changeset): |
|
266 | def url_func(changeset): | |
267 | tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \ |
|
267 | tooltip_html = "<div style='font-size:0.8em'><b>Author:</b>" + \ | |
268 |
" %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>" |
|
268 | " %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>" | |
269 |
|
269 | |||
270 | tooltip_html = tooltip_html % (changeset.author, |
|
270 | tooltip_html = tooltip_html % (changeset.author, | |
271 | changeset.date, |
|
271 | changeset.date, | |
272 | tooltip(changeset.message)) |
|
272 | tooltip(changeset.message)) | |
@@ -280,11 +280,11 b' def pygmentize_annotation(filenode, **kw' | |||||
280 | class_='tooltip', |
|
280 | class_='tooltip', | |
281 | tooltip_title=tooltip_html |
|
281 | tooltip_title=tooltip_html | |
282 | ) |
|
282 | ) | |
283 |
|
283 | |||
284 | uri += '\n' |
|
284 | uri += '\n' | |
285 |
return uri |
|
285 | return uri | |
286 | return literal(annotate_highlight(filenode, url_func, **kwargs)) |
|
286 | return literal(annotate_highlight(filenode, url_func, **kwargs)) | |
287 |
|
287 | |||
288 | def repo_name_slug(value): |
|
288 | def repo_name_slug(value): | |
289 | """Return slug of name of repository |
|
289 | """Return slug of name of repository | |
290 | This function is called on each creation/modification |
|
290 | This function is called on each creation/modification | |
@@ -292,7 +292,7 b' def repo_name_slug(value):' | |||||
292 | """ |
|
292 | """ | |
293 | slug = remove_formatting(value) |
|
293 | slug = remove_formatting(value) | |
294 | slug = strip_tags(slug) |
|
294 | slug = strip_tags(slug) | |
295 |
|
295 | |||
296 | for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """: |
|
296 | for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """: | |
297 | slug = slug.replace(c, '-') |
|
297 | slug = slug.replace(c, '-') | |
298 | slug = recursive_replace(slug, '-') |
|
298 | slug = recursive_replace(slug, '-') | |
@@ -305,7 +305,7 b' def get_changeset_safe(repo, rev):' | |||||
305 | if not isinstance(repo, BaseRepository): |
|
305 | if not isinstance(repo, BaseRepository): | |
306 | raise Exception('You must pass an Repository ' |
|
306 | raise Exception('You must pass an Repository ' | |
307 | 'object as first argument got %s', type(repo)) |
|
307 | 'object as first argument got %s', type(repo)) | |
308 |
|
308 | |||
309 | try: |
|
309 | try: | |
310 | cs = repo.get_changeset(rev) |
|
310 | cs = repo.get_changeset(rev) | |
311 | except RepositoryError: |
|
311 | except RepositoryError: | |
@@ -358,8 +358,8 b' def gravatar_url(email_address, size=30)' | |||||
358 | baseurl_nossl = "http://www.gravatar.com/avatar/" |
|
358 | baseurl_nossl = "http://www.gravatar.com/avatar/" | |
359 | baseurl_ssl = "https://secure.gravatar.com/avatar/" |
|
359 | baseurl_ssl = "https://secure.gravatar.com/avatar/" | |
360 | baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl |
|
360 | baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl | |
361 |
|
361 | |||
362 |
|
362 | |||
363 | # construct the url |
|
363 | # construct the url | |
364 | gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?" |
|
364 | gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?" | |
365 | gravatar_url += urllib.urlencode({'d':default, 's':str(size)}) |
|
365 | gravatar_url += urllib.urlencode({'d':default, 's':str(size)}) | |
@@ -370,7 +370,7 b' def safe_unicode(str):' | |||||
370 | """safe unicode function. In case of UnicodeDecode error we try to return |
|
370 | """safe unicode function. In case of UnicodeDecode error we try to return | |
371 | unicode with errors replace, if this failes we return unicode with |
|
371 | unicode with errors replace, if this failes we return unicode with | |
372 | string_escape decoding """ |
|
372 | string_escape decoding """ | |
373 |
|
373 | |||
374 | try: |
|
374 | try: | |
375 | u_str = unicode(str) |
|
375 | u_str = unicode(str) | |
376 | except UnicodeDecodeError: |
|
376 | except UnicodeDecodeError: | |
@@ -379,5 +379,5 b' def safe_unicode(str):' | |||||
379 | except UnicodeDecodeError: |
|
379 | except UnicodeDecodeError: | |
380 | #incase we have a decode error just represent as byte string |
|
380 | #incase we have a decode error just represent as byte string | |
381 | u_str = unicode(str(str).encode('string_escape')) |
|
381 | u_str = unicode(str(str).encode('string_escape')) | |
382 |
|
382 | |||
383 | return u_str |
|
383 | return u_str |
@@ -221,6 +221,11 b" def make_ui(read_from='file', path=None," | |||||
221 | for k, v in cfg.items(section): |
|
221 | for k, v in cfg.items(section): | |
222 | baseui.setconfig(section, k, v) |
|
222 | baseui.setconfig(section, k, v) | |
223 | log.debug('settings ui from file[%s]%s:%s', section, k, v) |
|
223 | log.debug('settings ui from file[%s]%s:%s', section, k, v) | |
|
224 | ||||
|
225 | for k, v in baseui.configitems('extensions'): | |||
|
226 | baseui.setconfig('extensions', k, '0') | |||
|
227 | #just enable mq | |||
|
228 | baseui.setconfig('extensions', 'mq', '1') | |||
224 | if checkpaths:check_repo_dir(cfg.items('paths')) |
|
229 | if checkpaths:check_repo_dir(cfg.items('paths')) | |
225 |
|
230 | |||
226 |
|
231 |
@@ -22,9 +22,9 b' class RhodeCodeUi(Base):' | |||||
22 | ui_key = Column("ui_key", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
22 | ui_key = Column("ui_key", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
23 | ui_value = Column("ui_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
23 | ui_value = Column("ui_value", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
24 | ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True) |
|
24 | ui_active = Column("ui_active", BOOLEAN(), nullable=True, unique=None, default=True) | |
25 |
|
25 | |||
26 |
|
26 | |||
27 |
class User(Base): |
|
27 | class User(Base): | |
28 | __tablename__ = 'users' |
|
28 | __tablename__ = 'users' | |
29 | __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True}) |
|
29 | __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True}) | |
30 | user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True) |
|
30 | user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True) | |
@@ -36,21 +36,21 b' class User(Base):' | |||||
36 | lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
36 | lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
37 | email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
37 | email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
38 | last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None) |
|
38 | last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None) | |
39 |
|
39 | |||
40 | user_log = relation('UserLog') |
|
40 | user_log = relation('UserLog') | |
41 | user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id") |
|
41 | user_perms = relation('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id") | |
42 |
|
42 | |||
43 | @LazyProperty |
|
43 | @LazyProperty | |
44 | def full_contact(self): |
|
44 | def full_contact(self): | |
45 | return '%s %s <%s>' % (self.name, self.lastname, self.email) |
|
45 | return '%s %s <%s>' % (self.name, self.lastname, self.email) | |
46 |
|
46 | |||
47 | def __repr__(self): |
|
47 | def __repr__(self): | |
48 | return "<User('id:%s:%s')>" % (self.user_id, self.username) |
|
48 | return "<User('id:%s:%s')>" % (self.user_id, self.username) | |
49 |
|
49 | |||
50 | def update_lastlogin(self): |
|
50 | def update_lastlogin(self): | |
51 | """Update user lastlogin""" |
|
51 | """Update user lastlogin""" | |
52 | import datetime |
|
52 | import datetime | |
53 |
|
53 | |||
54 | try: |
|
54 | try: | |
55 | session = Session.object_session(self) |
|
55 | session = Session.object_session(self) | |
56 | self.last_login = datetime.datetime.now() |
|
56 | self.last_login = datetime.datetime.now() | |
@@ -58,24 +58,24 b' class User(Base):' | |||||
58 | session.commit() |
|
58 | session.commit() | |
59 | log.debug('updated user %s lastlogin', self.username) |
|
59 | log.debug('updated user %s lastlogin', self.username) | |
60 | except Exception: |
|
60 | except Exception: | |
61 |
session.rollback() |
|
61 | session.rollback() | |
62 |
|
62 | |||
63 |
|
63 | |||
64 |
class UserLog(Base): |
|
64 | class UserLog(Base): | |
65 | __tablename__ = 'user_logs' |
|
65 | __tablename__ = 'user_logs' | |
66 | __table_args__ = {'useexisting':True} |
|
66 | __table_args__ = {'useexisting':True} | |
67 | user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True) |
|
67 | user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True) | |
68 | user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) |
|
68 | user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) | |
69 | repository_id = Column("repository_id", INTEGER(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None) |
|
69 | repository_id = Column("repository_id", INTEGER(length=None, convert_unicode=False, assert_unicode=None), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None) | |
70 | repository_name = Column("repository_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
70 | repository_name = Column("repository_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
71 |
user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
71 | user_ip = Column("user_ip", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
72 | action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
72 | action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
73 | action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None) |
|
73 | action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None) | |
74 | revision = Column('revision', TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
74 | revision = Column('revision', TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
75 |
|
75 | |||
76 | user = relation('User') |
|
76 | user = relation('User') | |
77 | repository = relation('Repository') |
|
77 | repository = relation('Repository') | |
78 |
|
78 | |||
79 | class Repository(Base): |
|
79 | class Repository(Base): | |
80 | __tablename__ = 'repositories' |
|
80 | __tablename__ = 'repositories' | |
81 | __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},) |
|
81 | __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},) | |
@@ -85,21 +85,23 b' class Repository(Base):' | |||||
85 | private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None) |
|
85 | private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None) | |
86 | description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
86 | description = Column("description", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
87 | fork_id = Column("fork_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None) |
|
87 | fork_id = Column("fork_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=True, unique=False, default=None) | |
88 |
|
88 | |||
89 | user = relation('User') |
|
89 | user = relation('User') | |
90 | fork = relation('Repository', remote_side=repo_id) |
|
90 | fork = relation('Repository', remote_side=repo_id) | |
91 | repo_to_perm = relation('RepoToPerm', cascade='all') |
|
91 | repo_to_perm = relation('RepoToPerm', cascade='all') | |
92 |
|
92 | stats = relation('Statistics', cascade='all') | ||
|
93 | ||||
|
94 | ||||
93 | def __repr__(self): |
|
95 | def __repr__(self): | |
94 | return "<Repository('id:%s:%s')>" % (self.repo_id, self.repo_name) |
|
96 | return "<Repository('id:%s:%s')>" % (self.repo_id, self.repo_name) | |
95 |
|
97 | |||
96 | class Permission(Base): |
|
98 | class Permission(Base): | |
97 | __tablename__ = 'permissions' |
|
99 | __tablename__ = 'permissions' | |
98 | __table_args__ = {'useexisting':True} |
|
100 | __table_args__ = {'useexisting':True} | |
99 | permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True) |
|
101 | permission_id = Column("permission_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True) | |
100 | permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
102 | permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
101 | permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) |
|
103 | permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) | |
102 |
|
104 | |||
103 | def __repr__(self): |
|
105 | def __repr__(self): | |
104 | return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name) |
|
106 | return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name) | |
105 |
|
107 | |||
@@ -109,8 +111,8 b' class RepoToPerm(Base):' | |||||
109 | repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True) |
|
111 | repo_to_perm_id = Column("repo_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True) | |
110 | user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) |
|
112 | user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) | |
111 | permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None) |
|
113 | permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None) | |
112 |
repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None) |
|
114 | repository_id = Column("repository_id", INTEGER(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=None, default=None) | |
113 |
|
115 | |||
114 | user = relation('User') |
|
116 | user = relation('User') | |
115 | permission = relation('Permission') |
|
117 | permission = relation('Permission') | |
116 | repository = relation('Repository') |
|
118 | repository = relation('Repository') | |
@@ -121,7 +123,7 b' class UserToPerm(Base):' | |||||
121 | user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True) |
|
123 | user_to_perm_id = Column("user_to_perm_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=True) | |
122 | user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) |
|
124 | user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=False, unique=None, default=None) | |
123 | permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None) |
|
125 | permission_id = Column("permission_id", INTEGER(), ForeignKey(u'permissions.permission_id'), nullable=False, unique=None, default=None) | |
124 |
|
126 | |||
125 | user = relation('User') |
|
127 | user = relation('User') | |
126 | permission = relation('Permission') |
|
128 | permission = relation('Permission') | |
127 |
|
129 | |||
@@ -134,6 +136,6 b' class Statistics(Base):' | |||||
134 | commit_activity = Column("commit_activity", BLOB(), nullable=False)#JSON data |
|
136 | commit_activity = Column("commit_activity", BLOB(), nullable=False)#JSON data | |
135 | commit_activity_combined = Column("commit_activity_combined", BLOB(), nullable=False)#JSON data |
|
137 | commit_activity_combined = Column("commit_activity_combined", BLOB(), nullable=False)#JSON data | |
136 | languages = Column("languages", BLOB(), nullable=False)#JSON data |
|
138 | languages = Column("languages", BLOB(), nullable=False)#JSON data | |
137 |
|
||||
138 | repository = relation('Repository') |
|
|||
139 |
|
139 | |||
|
140 | repository = relation('Repository', single_parent=True) | |||
|
141 |
@@ -270,7 +270,7 b' text-decoration:none;' | |||||
270 | } |
|
270 | } | |
271 |
|
271 | |||
272 | #header #header-inner #logo a:hover { |
|
272 | #header #header-inner #logo a:hover { | |
273 |
color:# |
|
273 | color:#bfe3ff; | |
274 | } |
|
274 | } | |
275 |
|
275 | |||
276 | #header #header-inner #quick,#header #header-inner #quick ul { |
|
276 | #header #header-inner #quick,#header #header-inner #quick ul { | |
@@ -419,7 +419,7 b' padding:12px 9px 7px 24px;' | |||||
419 | } |
|
419 | } | |
420 |
|
420 | |||
421 | #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover { |
|
421 | #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover { | |
422 |
background:url("../images/icons/ |
|
422 | background:url("../images/icons/database_edit.png") no-repeat scroll 4px 9px #FFF; | |
423 | width:167px; |
|
423 | width:167px; | |
424 | margin:0; |
|
424 | margin:0; | |
425 | padding:12px 9px 7px 24px; |
|
425 | padding:12px 9px 7px 24px; | |
@@ -1010,7 +1010,7 b' padding:0;' | |||||
1010 | #content div.box table th { |
|
1010 | #content div.box table th { | |
1011 | background:#eee; |
|
1011 | background:#eee; | |
1012 | border-bottom:1px solid #ddd; |
|
1012 | border-bottom:1px solid #ddd; | |
1013 |
padding: |
|
1013 | padding:5px 0px 5px 5px; | |
1014 | } |
|
1014 | } | |
1015 |
|
1015 | |||
1016 | #content div.box table th.left { |
|
1016 | #content div.box table th.left { | |
@@ -1393,7 +1393,6 b' background-color:#003367;' | |||||
1393 | color:#FFF; |
|
1393 | color:#FFF; | |
1394 | display:block; |
|
1394 | display:block; | |
1395 | min-width:20px; |
|
1395 | min-width:20px; | |
1396 | max-width:400px; |
|
|||
1397 | text-decoration:none; |
|
1396 | text-decoration:none; | |
1398 | height:12px; |
|
1397 | height:12px; | |
1399 | margin-bottom:4px; |
|
1398 | margin-bottom:4px; | |
@@ -1542,7 +1541,7 b' background:#F88;' | |||||
1542 |
|
1541 | |||
1543 | .right .merge { |
|
1542 | .right .merge { | |
1544 | vertical-align:top; |
|
1543 | vertical-align:top; | |
1545 |
font-size: |
|
1544 | font-size:0.75em; | |
1546 | font-weight:700; |
|
1545 | font-weight:700; | |
1547 | } |
|
1546 | } | |
1548 |
|
1547 | |||
@@ -1554,13 +1553,15 b' font-family:monospace;' | |||||
1554 | .right .logtags .branchtag { |
|
1553 | .right .logtags .branchtag { | |
1555 | background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px; |
|
1554 | background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px; | |
1556 | display:block; |
|
1555 | display:block; | |
1557 | padding:8px 16px 0 0; |
|
1556 | font-size:0.8em; | |
|
1557 | padding:11px 16px 0 0; | |||
1558 | } |
|
1558 | } | |
1559 |
|
1559 | |||
1560 | .right .logtags .tagtag { |
|
1560 | .right .logtags .tagtag { | |
1561 | background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px; |
|
1561 | background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px; | |
1562 | display:block; |
|
1562 | display:block; | |
1563 | padding:6px 18px 0 0; |
|
1563 | font-size:0.8em; | |
|
1564 | padding:11px 16px 0 0; | |||
1564 | } |
|
1565 | } | |
1565 |
|
1566 | |||
1566 | div.browserblock { |
|
1567 | div.browserblock { | |
@@ -1701,6 +1702,7 b' font:100% sans-serif;' | |||||
1701 | width:auto; |
|
1702 | width:auto; | |
1702 | opacity:1px; |
|
1703 | opacity:1px; | |
1703 | padding:8px; |
|
1704 | padding:8px; | |
|
1705 | white-space: pre; | |||
1704 | } |
|
1706 | } | |
1705 |
|
1707 | |||
1706 | .ac { |
|
1708 | .ac { | |
@@ -2024,7 +2026,6 b' display:block;' | |||||
2024 | } |
|
2026 | } | |
2025 |
|
2027 | |||
2026 | #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a { |
|
2028 | #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a { | |
2027 | background:url("../../images/title_tab_selected.png") no-repeat bottom center; |
|
|||
2028 | color:#bfe3ff; |
|
2029 | color:#bfe3ff; | |
2029 | } |
|
2030 | } | |
2030 |
|
2031 |
@@ -43,8 +43,8 b'' | |||||
43 | </tr> |
|
43 | </tr> | |
44 | %endif |
|
44 | %endif | |
45 |
|
45 | |||
46 |
%for cnt,node in enumerate(c.files_list |
|
46 | %for cnt,node in enumerate(c.files_list): | |
47 | <tr class="parity${cnt%2}"> |
|
47 | <tr class="parity${(cnt+1)%2}"> | |
48 | <td> |
|
48 | <td> | |
49 | ${h.link_to(node.name,h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=node.path),class_=file_class(node))} |
|
49 | ${h.link_to(node.name,h.url('files_home',repo_name=c.repo_name,revision=c.cur_rev,f_path=node.path),class_=file_class(node))} | |
50 | </td> |
|
50 | </td> | |
@@ -59,19 +59,19 b'' | |||||
59 | %endif |
|
59 | %endif | |
60 | </td> |
|
60 | </td> | |
61 | <td> |
|
61 | <td> | |
62 |
|
|
62 | %if node.is_file(): | |
63 |
|
|
63 | ${node.last_changeset.revision} | |
64 |
|
|
64 | %endif | |
65 | </td> |
|
65 | </td> | |
66 | <td> |
|
66 | <td> | |
67 |
|
|
67 | %if node.is_file(): | |
68 |
|
|
68 | ${h.age(node.last_changeset._ctx.date())} - ${node.last_changeset.date} | |
69 |
|
|
69 | %endif | |
70 | </td> |
|
70 | </td> | |
71 | <td> |
|
71 | <td> | |
72 |
|
|
72 | %if node.is_file(): | |
73 |
|
|
73 | ${node.last_changeset.author} | |
74 |
|
|
74 | %endif | |
75 | </td> |
|
75 | </td> | |
76 | </tr> |
|
76 | </tr> | |
77 | %endfor |
|
77 | %endfor |
@@ -131,11 +131,13 b' E.onDOMReady(function(e){' | |||||
131 | var value = data[k]; |
|
131 | var value = data[k]; | |
132 | var td1 = document.createElement('td'); |
|
132 | var td1 = document.createElement('td'); | |
133 | td1.width=150; |
|
133 | td1.width=150; | |
|
134 | ||||
134 | var trending_language_label = document.createElement('div'); |
|
135 | var trending_language_label = document.createElement('div'); | |
135 | trending_language_label.innerHTML = k; |
|
136 | trending_language_label.innerHTML = k; | |
136 | td1.appendChild(trending_language_label); |
|
137 | td1.appendChild(trending_language_label); | |
137 |
|
138 | |||
138 | var td2 = document.createElement('td'); |
|
139 | var td2 = document.createElement('td'); | |
|
140 | td2.setAttribute('style','padding-right: 12px ! important;'); | |||
139 | var trending_language = document.createElement('div'); |
|
141 | var trending_language = document.createElement('div'); | |
140 | trending_language.title = k; |
|
142 | trending_language.title = k; | |
141 | trending_language.innerHTML = "<b>"+percentage+"% "+value+" ${_('files')}</b>"; |
|
143 | trending_language.innerHTML = "<b>"+percentage+"% "+value+" ${_('files')}</b>"; |
General Comments 0
You need to be logged in to leave comments.
Login now