Commit b3108e39972cb29c7da6cf724e74fc6bbf1269bb
1 parent
1e7861da
Exists in
master
and in
13 other branches
Fixing and extracting Trac dependencies
-Trac filters and search options only show if trac enabled -Chart only shows trac data if enabled -Fix rollback migration of Trac Signed-off-by: Gustavo Jaruga <darksshades@gmail.com> Signed-off-by: Matheus Faria <matheus.sousa.faria@gmail.com>
Showing
14 changed files
with
365 additions
and
350 deletions
Show diff stats
src/accounts/search_indexes.py
src/accounts/views.py
| ... | ... | @@ -25,7 +25,7 @@ from haystack.query import SearchQuerySet |
| 25 | 25 | from super_archives.models import EmailAddress, Message |
| 26 | 26 | from super_archives.utils.email import send_email_lists |
| 27 | 27 | from search.utils import trans |
| 28 | -from proxy.trac.models import WikiCollabCount, TicketCollabCount | |
| 28 | +from proxy.models import WikiCollabCount, TicketCollabCount | |
| 29 | 29 | from .forms import (UserCreationForm, ListsForm, UserUpdateForm, |
| 30 | 30 | ChangeXMPPPasswordForm) |
| 31 | 31 | from .errors import XMPPChangePwdException | ... | ... |
src/api/resources.py
| ... | ... | @@ -7,7 +7,7 @@ from tastypie.constants import ALL_WITH_RELATIONS, ALL |
| 7 | 7 | from tastypie.resources import ModelResource |
| 8 | 8 | |
| 9 | 9 | from super_archives.models import Message, EmailAddress |
| 10 | -from proxy.trac.models import Revision, Ticket, Wiki | |
| 10 | +from proxy.models import Revision, Ticket, Wiki | |
| 11 | 11 | |
| 12 | 12 | |
| 13 | 13 | User = get_user_model() | ... | ... |
src/badger/utils.py
src/colab/custom_settings.py
| ... | ... | @@ -255,18 +255,6 @@ MESSAGE_TAGS = { |
| 255 | 255 | messages.ERROR: 'alert-danger', |
| 256 | 256 | } |
| 257 | 257 | |
| 258 | - | |
| 259 | -### Trac | |
| 260 | -TRAC_ENABLED = False | |
| 261 | - | |
| 262 | -if TRAC_ENABLED: | |
| 263 | - from trac_settings import * | |
| 264 | - DATABASES['trac'] = TRAC_DATABASE | |
| 265 | - INSTALLED_APPS = INSTALLED_APPS + ( | |
| 266 | - 'proxy.trac', | |
| 267 | - ) | |
| 268 | - | |
| 269 | - | |
| 270 | 258 | ### Feedzilla (planet) |
| 271 | 259 | from feedzilla.settings import * |
| 272 | 260 | FEEDZILLA_PAGE_SIZE = 5 |
| ... | ... | @@ -321,7 +309,19 @@ DPASTE_EXPIRE_DEFAULT = DPASTE_EXPIRE_CHOICES[4][0] |
| 321 | 309 | DPASTE_DEFAULT_GIST_DESCRIPTION = 'Gist created on Colab Interlegis' |
| 322 | 310 | DPASTE_DEFAULT_GIST_NAME = 'colab_paste' |
| 323 | 311 | |
| 312 | + | |
| 313 | +### Trac | |
| 314 | +TRAC_ENABLED = False | |
| 315 | + | |
| 316 | +from trac_settings import * | |
| 317 | +DATABASES['trac'] = TRAC_DATABASE | |
| 318 | + | |
| 324 | 319 | try: |
| 325 | 320 | from local_settings import * |
| 326 | 321 | except ImportError: |
| 327 | 322 | pass |
| 323 | + | |
| 324 | +if TRAC_ENABLED: | |
| 325 | + INSTALLED_APPS = INSTALLED_APPS + ( | |
| 326 | + 'proxy.trac', | |
| 327 | + ) | |
| 328 | 328 | \ No newline at end of file | ... | ... |
src/home/views.py
| ... | ... | @@ -9,7 +9,7 @@ from django.http import HttpResponse, Http404 |
| 9 | 9 | from search.utils import trans |
| 10 | 10 | from haystack.query import SearchQuerySet |
| 11 | 11 | |
| 12 | -from proxy.trac.models import WikiCollabCount, TicketCollabCount | |
| 12 | +from proxy.models import WikiCollabCount, TicketCollabCount | |
| 13 | 13 | from super_archives.models import Thread |
| 14 | 14 | |
| 15 | 15 | |
| ... | ... | @@ -23,12 +23,16 @@ def index(request): |
| 23 | 23 | count_types = cache.get('home_chart') |
| 24 | 24 | if count_types is None: |
| 25 | 25 | count_types = OrderedDict() |
| 26 | - for type in ['thread', 'changeset', 'attachment']: | |
| 27 | - count_types[type] = SearchQuerySet().filter( | |
| 28 | - type=type, | |
| 29 | - ).count() | |
| 26 | + count_types['thread'] = SearchQuerySet().filter( | |
| 27 | + type='thread', | |
| 28 | + ).count() | |
| 30 | 29 | |
| 31 | 30 | if settings.TRAC_ENABLED: |
| 31 | + for type in ['changeset', 'attachment']: | |
| 32 | + count_types[type] = SearchQuerySet().filter( | |
| 33 | + type=type, | |
| 34 | + ).count() | |
| 35 | + | |
| 32 | 36 | count_types['ticket'] = sum([ |
| 33 | 37 | ticket.count for ticket in TicketCollabCount.objects.all() |
| 34 | 38 | ]) | ... | ... |
src/proxy/models.py
| 1 | 1 | # -*- coding: utf-8 -*- |
| 2 | 2 | from django.db import models |
| 3 | 3 | from django.conf import settings |
| 4 | +import os | |
| 5 | +import urllib2 | |
| 4 | 6 | |
| 5 | -if settings.TRAC_ENABLED: | |
| 6 | - import trac.trac.models | |
| 7 | +from django.conf import settings | |
| 8 | +from django.db import models, connections | |
| 9 | +from django.db.models.signals import post_save | |
| 10 | +from django.dispatch import receiver | |
| 11 | + | |
| 12 | +from accounts.models import User | |
| 13 | +from hitcounter.models import HitCounterModelMixin | |
| 14 | + | |
| 15 | +class Attachment(models.Model, HitCounterModelMixin): | |
| 16 | + url = models.TextField(primary_key=True) | |
| 17 | + attach_id = models.TextField() | |
| 18 | + used_by = models.TextField() | |
| 19 | + filename = models.TextField() | |
| 20 | + author = models.TextField(blank=True) | |
| 21 | + description = models.TextField(blank=True) | |
| 22 | + created = models.DateTimeField(blank=True) | |
| 23 | + mimetype = models.TextField(blank=True) | |
| 24 | + size = models.IntegerField(blank=True) | |
| 25 | + | |
| 26 | + class Meta: | |
| 27 | + managed = False | |
| 28 | + db_table = 'attachment_view' | |
| 29 | + | |
| 30 | + @property | |
| 31 | + def filepath(self): | |
| 32 | + return os.path.join( | |
| 33 | + settings.ATTACHMENTS_FOLDER_PATH, | |
| 34 | + self.used_by, | |
| 35 | + self.attach_id, | |
| 36 | + urllib2.quote(self.filename.encode('utf8')) | |
| 37 | + ) | |
| 38 | + | |
| 39 | + def get_absolute_url(self): | |
| 40 | + return u'/raw-attachment/{}'.format(self.url) | |
| 41 | + | |
| 42 | + def get_author(self): | |
| 43 | + try: | |
| 44 | + return User.objects.get(username=self.author) | |
| 45 | + except User.DoesNotExist: | |
| 46 | + return None | |
| 47 | + | |
| 48 | + | |
| 49 | +class Revision(models.Model, HitCounterModelMixin): | |
| 50 | + key = models.TextField(blank=True, primary_key=True) | |
| 51 | + rev = models.TextField(blank=True) | |
| 52 | + author = models.TextField(blank=True) | |
| 53 | + message = models.TextField(blank=True) | |
| 54 | + repository_name = models.TextField(blank=True) | |
| 55 | + created = models.DateTimeField(blank=True, null=True) | |
| 56 | + | |
| 57 | + class Meta: | |
| 58 | + managed = False | |
| 59 | + db_table = 'revision_view' | |
| 60 | + | |
| 61 | + def get_absolute_url(self): | |
| 62 | + return u'/changeset/{}/{}'.format(self.rev, self.repository_name) | |
| 63 | + | |
| 64 | + def get_author(self): | |
| 65 | + try: | |
| 66 | + return User.objects.get(username=self.author) | |
| 67 | + except User.DoesNotExist: | |
| 68 | + return None | |
| 69 | + | |
| 70 | +class Ticket(models.Model, HitCounterModelMixin): | |
| 71 | + id = models.IntegerField(primary_key=True) | |
| 72 | + summary = models.TextField(blank=True) | |
| 73 | + description = models.TextField(blank=True) | |
| 74 | + milestone = models.TextField(blank=True) | |
| 75 | + priority = models.TextField(blank=True) | |
| 76 | + component = models.TextField(blank=True) | |
| 77 | + version = models.TextField(blank=True) | |
| 78 | + severity = models.TextField(blank=True) | |
| 79 | + reporter = models.TextField(blank=True) | |
| 80 | + author = models.TextField(blank=True) | |
| 81 | + status = models.TextField(blank=True) | |
| 82 | + keywords = models.TextField(blank=True) | |
| 83 | + collaborators = models.TextField(blank=True) | |
| 84 | + created = models.DateTimeField(blank=True, null=True) | |
| 85 | + modified = models.DateTimeField(blank=True, null=True) | |
| 86 | + modified_by = models.TextField(blank=True) | |
| 87 | + | |
| 88 | + class Meta: | |
| 89 | + managed = False | |
| 90 | + db_table = 'ticket_view' | |
| 91 | + | |
| 92 | + def get_absolute_url(self): | |
| 93 | + return u'/ticket/{}'.format(self.id) | |
| 94 | + | |
| 95 | + def get_author(self): | |
| 96 | + try: | |
| 97 | + return User.objects.get(username=self.author) | |
| 98 | + except User.DoesNotExist: | |
| 99 | + return None | |
| 100 | + | |
| 101 | + def get_modified_by(self): | |
| 102 | + try: | |
| 103 | + return User.objects.get(username=self.modified_by) | |
| 104 | + except User.DoesNotExist: | |
| 105 | + return None | |
| 106 | + | |
| 107 | +class Wiki(models.Model, HitCounterModelMixin): | |
| 108 | + name = models.TextField(primary_key=True) | |
| 109 | + wiki_text = models.TextField(blank=True) | |
| 110 | + author = models.TextField(blank=True) | |
| 111 | + collaborators = models.TextField(blank=True) | |
| 112 | + created = models.DateTimeField(blank=True, null=True) | |
| 113 | + modified = models.DateTimeField(blank=True, null=True) | |
| 114 | + modified_by = models.TextField(blank=True) | |
| 115 | + | |
| 116 | + class Meta: | |
| 117 | + managed = False | |
| 118 | + db_table = 'wiki_view' | |
| 119 | + | |
| 120 | + def get_absolute_url(self): | |
| 121 | + return u'/wiki/{}'.format(self.name) | |
| 122 | + | |
| 123 | + def get_author(self): | |
| 124 | + try: | |
| 125 | + return User.objects.get(username=self.author) | |
| 126 | + except User.DoesNotExist: | |
| 127 | + return None | |
| 128 | + | |
| 129 | + def get_modified_by(self): | |
| 130 | + try: | |
| 131 | + return User.objects.get(username=self.modified_by) | |
| 132 | + except User.DoesNotExist: | |
| 133 | + return None | |
| 134 | + | |
| 135 | + | |
| 136 | +class WikiCollabCount(models.Model): | |
| 137 | + author = models.TextField(primary_key=True) | |
| 138 | + count = models.IntegerField() | |
| 139 | + | |
| 140 | + class Meta: | |
| 141 | + managed = False | |
| 142 | + db_table = 'wiki_collab_count_view' | |
| 143 | + | |
| 144 | + | |
| 145 | +class TicketCollabCount(models.Model): | |
| 146 | + author = models.TextField(primary_key=True) | |
| 147 | + count = models.IntegerField() | |
| 148 | + | |
| 149 | + class Meta: | |
| 150 | + managed = False | |
| 151 | + db_table = 'ticket_collab_count_view' | |
| 152 | + | |
| 153 | + | |
| 154 | +@receiver(post_save, sender=User) | |
| 155 | +def change_session_attribute_email(sender, instance, **kwargs): | |
| 156 | + cursor = connections['trac'].cursor() | |
| 157 | + | |
| 158 | + cursor.execute(("UPDATE session_attribute SET value=%s " | |
| 159 | + "WHERE name='email' AND sid=%s"), | |
| 160 | + [instance.email, instance.username]) | |
| 161 | + cursor.execute(("UPDATE session_attribute SET value=%s " | |
| 162 | + "WHERE name='name' AND sid=%s"), | |
| 163 | + [instance.get_full_name(), instance.username]) | |
| 164 | + | |
| 165 | + cursor.execute(("INSERT INTO session_attribute " | |
| 166 | + "(sid, authenticated, name, value) " | |
| 167 | + "SELECT %s, '1', 'email', %s WHERE NOT EXISTS " | |
| 168 | + "(SELECT 1 FROM session_attribute WHERE sid=%s " | |
| 169 | + "AND name='email')"), | |
| 170 | + [instance.username, instance.email, instance.username]) | |
| 171 | + | |
| 172 | + cursor.execute(("INSERT INTO session_attribute " | |
| 173 | + "(sid, authenticated, name, value) " | |
| 174 | + "SELECT %s, '1', 'name', %s WHERE NOT EXISTS " | |
| 175 | + "(SELECT 1 FROM session_attribute WHERE sid=%s " | |
| 176 | + "AND name='name')"), | |
| 177 | + [instance.username, instance.get_full_name(), | |
| 178 | + instance.username]) | ... | ... |
src/proxy/search_indexes.py
| ... | ... | @@ -9,7 +9,7 @@ from haystack import indexes |
| 9 | 9 | from haystack.utils import log as logging |
| 10 | 10 | |
| 11 | 11 | from search.base_indexes import BaseIndex |
| 12 | -from trac.models import Attachment, Ticket, Wiki, Revision | |
| 12 | +from proxy.models import Attachment, Ticket, Wiki, Revision | |
| 13 | 13 | |
| 14 | 14 | |
| 15 | 15 | logger = logging.getLogger('haystack') | ... | ... |
src/proxy/trac/migrations/0001_initial.py
| ... | ... | @@ -9,7 +9,7 @@ from django.db import models |
| 9 | 9 | class Migration(SchemaMigration): |
| 10 | 10 | |
| 11 | 11 | def forwards(self, orm): |
| 12 | - connection = connections['trac'] | |
| 12 | + connection = connections['trac'] | |
| 13 | 13 | |
| 14 | 14 | cursor = connection.cursor() |
| 15 | 15 | cursor.execute(''' |
| ... | ... | @@ -60,111 +60,111 @@ class Migration(SchemaMigration): |
| 60 | 60 | ); |
| 61 | 61 | ''') |
| 62 | 62 | cursor.execute(''' |
| 63 | -CREATE OR REPLACE VIEW revision_view AS SELECT | |
| 64 | -revision.rev, | |
| 65 | -revision.author, | |
| 66 | -revision.message, | |
| 67 | -repository.value AS repository_name, | |
| 68 | -TIMESTAMP WITH TIME ZONE 'epoch' + (revision.time/1000000) * INTERVAL '1s' AS created, | |
| 69 | -CONCAT(revision.repos, '-', revision.rev) AS key | |
| 70 | -FROM revision | |
| 71 | -INNER JOIN repository ON( | |
| 72 | -repository.id = revision.repos | |
| 73 | -AND repository.name = 'name' | |
| 74 | -AND repository.value != '' | |
| 75 | -); | |
| 76 | -''') | |
| 63 | + CREATE OR REPLACE VIEW revision_view AS SELECT | |
| 64 | + revision.rev, | |
| 65 | + revision.author, | |
| 66 | + revision.message, | |
| 67 | + repository.value AS repository_name, | |
| 68 | + TIMESTAMP WITH TIME ZONE 'epoch' + (revision.time/1000000) * INTERVAL '1s' AS created, | |
| 69 | + CONCAT(revision.repos, '-', revision.rev) AS key | |
| 70 | + FROM revision | |
| 71 | + INNER JOIN repository ON( | |
| 72 | + repository.id = revision.repos | |
| 73 | + AND repository.name = 'name' | |
| 74 | + AND repository.value != '' | |
| 75 | + ); | |
| 76 | + ''') | |
| 77 | 77 | cursor.execute(''' |
| 78 | -CREATE OR REPLACE VIEW attachment_view AS SELECT | |
| 79 | -CONCAT(attachment.type, '/' , attachment.id, '/', attachment.filename) AS url, | |
| 80 | -attachment.type AS used_by, | |
| 81 | -attachment.filename AS filename, | |
| 82 | -attachment.id as attach_id, | |
| 83 | -(SELECT LOWER(SUBSTRING(attachment.filename FROM '\.(\w+)$'))) AS mimetype, | |
| 84 | -attachment.author AS author, | |
| 85 | -attachment.description AS description, | |
| 86 | -attachment.size AS size, | |
| 87 | -TIMESTAMP WITH TIME ZONE 'epoch' + (attachment.time/1000000)* INTERVAL '1s' AS created | |
| 88 | -FROM attachment; | |
| 89 | -''') | |
| 78 | + CREATE OR REPLACE VIEW attachment_view AS SELECT | |
| 79 | + CONCAT(attachment.type, '/' , attachment.id, '/', attachment.filename) AS url, | |
| 80 | + attachment.type AS used_by, | |
| 81 | + attachment.filename AS filename, | |
| 82 | + attachment.id as attach_id, | |
| 83 | + (SELECT LOWER(SUBSTRING(attachment.filename FROM '\.(\w+)$'))) AS mimetype, | |
| 84 | + attachment.author AS author, | |
| 85 | + attachment.description AS description, | |
| 86 | + attachment.size AS size, | |
| 87 | + TIMESTAMP WITH TIME ZONE 'epoch' + (attachment.time/1000000)* INTERVAL '1s' AS created | |
| 88 | + FROM attachment; | |
| 89 | + ''') | |
| 90 | 90 | cursor.execute(''' |
| 91 | -CREATE OR REPLACE VIEW wiki_view AS SELECT | |
| 92 | -wiki.name AS name, | |
| 93 | -(SELECT wiki2.text FROM wiki AS wiki2 WHERE wiki2.name = wiki.name | |
| 94 | -AND wiki2.version = MAX(wiki.version)) AS wiki_text, | |
| 95 | -(SELECT wiki3.author FROM wiki AS wiki3 WHERE wiki3.name = wiki.name | |
| 96 | -AND wiki3.version = 1) AS author, | |
| 97 | -string_agg(DISTINCT wiki.author, ', ') AS collaborators, | |
| 98 | -TIMESTAMP WITH TIME ZONE 'epoch' + (MIN(wiki.time)/1000000) * INTERVAL '1s' AS created, | |
| 99 | -TIMESTAMP WITH TIME ZONE 'epoch' + (MAX(wiki.time)/1000000) * INTERVAL '1s' AS modified | |
| 100 | -FROM wiki | |
| 101 | -GROUP BY wiki.name; | |
| 102 | -''') | |
| 91 | + CREATE OR REPLACE VIEW wiki_view AS SELECT | |
| 92 | + wiki.name AS name, | |
| 93 | + (SELECT wiki2.text FROM wiki AS wiki2 WHERE wiki2.name = wiki.name | |
| 94 | + AND wiki2.version = MAX(wiki.version)) AS wiki_text, | |
| 95 | + (SELECT wiki3.author FROM wiki AS wiki3 WHERE wiki3.name = wiki.name | |
| 96 | + AND wiki3.version = 1) AS author, | |
| 97 | + string_agg(DISTINCT wiki.author, ', ') AS collaborators, | |
| 98 | + TIMESTAMP WITH TIME ZONE 'epoch' + (MIN(wiki.time)/1000000) * INTERVAL '1s' AS created, | |
| 99 | + TIMESTAMP WITH TIME ZONE 'epoch' + (MAX(wiki.time)/1000000) * INTERVAL '1s' AS modified | |
| 100 | + FROM wiki | |
| 101 | + GROUP BY wiki.name; | |
| 102 | + ''') | |
| 103 | 103 | cursor.execute(''' |
| 104 | -CREATE OR REPLACE VIEW wiki_view AS SELECT | |
| 105 | -wiki.name AS name, | |
| 106 | -(SELECT wiki2.text FROM wiki AS wiki2 WHERE wiki2.name = wiki.name | |
| 107 | -AND wiki2.version = MAX(wiki.version)) AS wiki_text, | |
| 108 | -(SELECT wiki3.author FROM wiki AS wiki3 WHERE wiki3.name = wiki.name | |
| 109 | -AND wiki3.version = 1) AS author, | |
| 110 | -string_agg(DISTINCT wiki.author, ', ') AS collaborators, | |
| 111 | -TIMESTAMP WITH TIME ZONE 'epoch' + (MIN(wiki.time)/1000000) * INTERVAL '1s' AS created, | |
| 112 | -TIMESTAMP WITH TIME ZONE 'epoch' + (MAX(wiki.time)/1000000) * INTERVAL '1s' AS modified, | |
| 113 | -(SELECT wiki4.author FROM wiki AS wiki4 WHERE wiki4.name = wiki.name | |
| 114 | -AND wiki4.version = MAX(wiki.version)) AS modified_by | |
| 115 | -FROM wiki | |
| 116 | -GROUP BY wiki.name; | |
| 104 | + CREATE OR REPLACE VIEW wiki_view AS SELECT | |
| 105 | + wiki.name AS name, | |
| 106 | + (SELECT wiki2.text FROM wiki AS wiki2 WHERE wiki2.name = wiki.name | |
| 107 | + AND wiki2.version = MAX(wiki.version)) AS wiki_text, | |
| 108 | + (SELECT wiki3.author FROM wiki AS wiki3 WHERE wiki3.name = wiki.name | |
| 109 | + AND wiki3.version = 1) AS author, | |
| 110 | + string_agg(DISTINCT wiki.author, ', ') AS collaborators, | |
| 111 | + TIMESTAMP WITH TIME ZONE 'epoch' + (MIN(wiki.time)/1000000) * INTERVAL '1s' AS created, | |
| 112 | + TIMESTAMP WITH TIME ZONE 'epoch' + (MAX(wiki.time)/1000000) * INTERVAL '1s' AS modified, | |
| 113 | + (SELECT wiki4.author FROM wiki AS wiki4 WHERE wiki4.name = wiki.name | |
| 114 | + AND wiki4.version = MAX(wiki.version)) AS modified_by | |
| 115 | + FROM wiki | |
| 116 | + GROUP BY wiki.name; | |
| 117 | 117 | |
| 118 | -CREATE OR REPLACE VIEW ticket_view AS SELECT | |
| 119 | -ticket.id AS id, | |
| 120 | -ticket.summary as summary, | |
| 121 | -ticket.description as description, | |
| 122 | -ticket.milestone as milestone, | |
| 123 | -ticket.priority as priority, | |
| 124 | -ticket.component as component, | |
| 125 | -ticket.version as version, | |
| 126 | -ticket.severity as severity, | |
| 127 | -ticket.reporter as reporter, | |
| 128 | -ticket.reporter as author, | |
| 129 | -ticket.status as status, | |
| 130 | -ticket.keywords as keywords, | |
| 131 | -(SELECT | |
| 132 | -string_agg(DISTINCT ticket_change.author, ', ') | |
| 133 | -FROM ticket_change WHERE ticket_change.ticket = ticket.id | |
| 134 | -GROUP BY ticket_change.ticket) as collaborators, | |
| 135 | -TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000000)* INTERVAL '1s' AS created, | |
| 136 | -TIMESTAMP WITH TIME ZONE 'epoch' + (changetime/1000000) * INTERVAL '1s' AS modified, | |
| 137 | -(SELECT | |
| 138 | -ticket_change.author | |
| 139 | -FROM ticket_change | |
| 140 | -WHERE ticket_change.ticket = ticket.id | |
| 141 | -AND ticket_change.time = ticket.changetime | |
| 142 | -LIMIT 1 | |
| 143 | -) AS modified_by | |
| 144 | -FROM ticket; | |
| 145 | -''') | |
| 118 | + CREATE OR REPLACE VIEW ticket_view AS SELECT | |
| 119 | + ticket.id AS id, | |
| 120 | + ticket.summary as summary, | |
| 121 | + ticket.description as description, | |
| 122 | + ticket.milestone as milestone, | |
| 123 | + ticket.priority as priority, | |
| 124 | + ticket.component as component, | |
| 125 | + ticket.version as version, | |
| 126 | + ticket.severity as severity, | |
| 127 | + ticket.reporter as reporter, | |
| 128 | + ticket.reporter as author, | |
| 129 | + ticket.status as status, | |
| 130 | + ticket.keywords as keywords, | |
| 131 | + (SELECT | |
| 132 | + string_agg(DISTINCT ticket_change.author, ', ') | |
| 133 | + FROM ticket_change WHERE ticket_change.ticket = ticket.id | |
| 134 | + GROUP BY ticket_change.ticket) as collaborators, | |
| 135 | + TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000000)* INTERVAL '1s' AS created, | |
| 136 | + TIMESTAMP WITH TIME ZONE 'epoch' + (changetime/1000000) * INTERVAL '1s' AS modified, | |
| 137 | + (SELECT | |
| 138 | + ticket_change.author | |
| 139 | + FROM ticket_change | |
| 140 | + WHERE ticket_change.ticket = ticket.id | |
| 141 | + AND ticket_change.time = ticket.changetime | |
| 142 | + LIMIT 1 | |
| 143 | + ) AS modified_by | |
| 144 | + FROM ticket; | |
| 145 | + ''') | |
| 146 | 146 | cursor.execute(''' |
| 147 | -CREATE OR REPLACE VIEW ticket_collab_count_view AS | |
| 148 | -SELECT | |
| 149 | -COALESCE (t1.author, t2.author) as author, | |
| 150 | -(COALESCE(t1.count, 0) + COALESCE(t2.count, 0)) as count | |
| 151 | -FROM | |
| 152 | -(SELECT author, count(*) as count | |
| 153 | -FROM ticket_change | |
| 154 | -GROUP BY author | |
| 155 | -ORDER BY author | |
| 156 | -) AS t1 | |
| 157 | -FULL OUTER JOIN | |
| 158 | -(SELECT reporter as author, count(*) as count | |
| 159 | -FROM ticket | |
| 160 | -GROUP BY reporter | |
| 161 | -ORDER BY reporter | |
| 162 | -) AS t2 | |
| 163 | -ON t1.author = t2.author; | |
| 147 | + CREATE OR REPLACE VIEW ticket_collab_count_view AS | |
| 148 | + SELECT | |
| 149 | + COALESCE (t1.author, t2.author) as author, | |
| 150 | + (COALESCE(t1.count, 0) + COALESCE(t2.count, 0)) as count | |
| 151 | + FROM | |
| 152 | + (SELECT author, count(*) as count | |
| 153 | + FROM ticket_change | |
| 154 | + GROUP BY author | |
| 155 | + ORDER BY author | |
| 156 | + ) AS t1 | |
| 157 | + FULL OUTER JOIN | |
| 158 | + (SELECT reporter as author, count(*) as count | |
| 159 | + FROM ticket | |
| 160 | + GROUP BY reporter | |
| 161 | + ORDER BY reporter | |
| 162 | + ) AS t2 | |
| 163 | + ON t1.author = t2.author; | |
| 164 | 164 | |
| 165 | -CREATE OR REPLACE VIEW wiki_collab_count_view AS | |
| 166 | -SELECT author, count(*) from wiki GROUP BY author; | |
| 167 | -''') | |
| 165 | + CREATE OR REPLACE VIEW wiki_collab_count_view AS | |
| 166 | + SELECT author, count(*) from wiki GROUP BY author; | |
| 167 | + ''') | |
| 168 | 168 | |
| 169 | 169 | pass |
| 170 | 170 | |
| ... | ... | @@ -173,13 +173,15 @@ SELECT author, count(*) from wiki GROUP BY author; |
| 173 | 173 | |
| 174 | 174 | cursor = connection.cursor() |
| 175 | 175 | cursor.execute(''' |
| 176 | -DROP VIEW IF EXISTS revision_view; | |
| 177 | -DROP VIEW IF EXISTS ticket_view; | |
| 178 | -DROP VIEW IF EXISTS wiki_view; | |
| 179 | -''') | |
| 180 | - cursor.execute('DROP VIEW IF EXISTS attachment_view;') | |
| 176 | + DROP VIEW IF EXISTS revision_view; | |
| 177 | + DROP VIEW IF EXISTS ticket_view; | |
| 178 | + DROP VIEW IF EXISTS wiki_view; | |
| 179 | + DROP VIEW IF EXISTS ticket_collab_count_view; | |
| 180 | + DROP VIEW IF EXISTS wiki_collab_count_view; | |
| 181 | + DROP VIEW IF EXISTS attachment_view; | |
| 182 | + ''') | |
| 181 | 183 | |
| 182 | - pass | |
| 184 | + pass | |
| 183 | 185 | |
| 184 | 186 | models = { |
| 185 | 187 | u'proxy.attachment': { |
| ... | ... | @@ -245,4 +247,4 @@ DROP VIEW IF EXISTS wiki_view; |
| 245 | 247 | } |
| 246 | 248 | |
| 247 | 249 | complete_apps = ['proxy'] |
| 248 | 250 | - symmetrical = True |
| 251 | + symmetrical = True | |
| 249 | 252 | \ No newline at end of file | ... | ... |
src/proxy/trac/models.py
| ... | ... | @@ -1,178 +0,0 @@ |
| 1 | -# -*- coding: utf-8 -*- | |
| 2 | - | |
| 3 | -import os | |
| 4 | -import urllib2 | |
| 5 | - | |
| 6 | -from django.conf import settings | |
| 7 | -from django.db import models, connections | |
| 8 | -from django.db.models.signals import post_save | |
| 9 | -from django.dispatch import receiver | |
| 10 | - | |
| 11 | -from accounts.models import User | |
| 12 | -from hitcounter.models import HitCounterModelMixin | |
| 13 | - | |
| 14 | - | |
| 15 | -class Attachment(models.Model, HitCounterModelMixin): | |
| 16 | - url = models.TextField(primary_key=True) | |
| 17 | - attach_id = models.TextField() | |
| 18 | - used_by = models.TextField() | |
| 19 | - filename = models.TextField() | |
| 20 | - author = models.TextField(blank=True) | |
| 21 | - description = models.TextField(blank=True) | |
| 22 | - created = models.DateTimeField(blank=True) | |
| 23 | - mimetype = models.TextField(blank=True) | |
| 24 | - size = models.IntegerField(blank=True) | |
| 25 | - | |
| 26 | - class Meta: | |
| 27 | - managed = False | |
| 28 | - db_table = 'attachment_view' | |
| 29 | - | |
| 30 | - @property | |
| 31 | - def filepath(self): | |
| 32 | - return os.path.join( | |
| 33 | - settings.ATTACHMENTS_FOLDER_PATH, | |
| 34 | - self.used_by, | |
| 35 | - self.attach_id, | |
| 36 | - urllib2.quote(self.filename.encode('utf8')) | |
| 37 | - ) | |
| 38 | - | |
| 39 | - def get_absolute_url(self): | |
| 40 | - return u'/raw-attachment/{}'.format(self.url) | |
| 41 | - | |
| 42 | - def get_author(self): | |
| 43 | - try: | |
| 44 | - return User.objects.get(username=self.author) | |
| 45 | - except User.DoesNotExist: | |
| 46 | - return None | |
| 47 | - | |
| 48 | - | |
| 49 | -class Revision(models.Model, HitCounterModelMixin): | |
| 50 | - key = models.TextField(blank=True, primary_key=True) | |
| 51 | - rev = models.TextField(blank=True) | |
| 52 | - author = models.TextField(blank=True) | |
| 53 | - message = models.TextField(blank=True) | |
| 54 | - repository_name = models.TextField(blank=True) | |
| 55 | - created = models.DateTimeField(blank=True, null=True) | |
| 56 | - | |
| 57 | - class Meta: | |
| 58 | - managed = False | |
| 59 | - db_table = 'revision_view' | |
| 60 | - | |
| 61 | - def get_absolute_url(self): | |
| 62 | - return u'/changeset/{}/{}'.format(self.rev, self.repository_name) | |
| 63 | - | |
| 64 | - def get_author(self): | |
| 65 | - try: | |
| 66 | - return User.objects.get(username=self.author) | |
| 67 | - except User.DoesNotExist: | |
| 68 | - return None | |
| 69 | - | |
| 70 | -class Ticket(models.Model, HitCounterModelMixin): | |
| 71 | - id = models.IntegerField(primary_key=True) | |
| 72 | - summary = models.TextField(blank=True) | |
| 73 | - description = models.TextField(blank=True) | |
| 74 | - milestone = models.TextField(blank=True) | |
| 75 | - priority = models.TextField(blank=True) | |
| 76 | - component = models.TextField(blank=True) | |
| 77 | - version = models.TextField(blank=True) | |
| 78 | - severity = models.TextField(blank=True) | |
| 79 | - reporter = models.TextField(blank=True) | |
| 80 | - author = models.TextField(blank=True) | |
| 81 | - status = models.TextField(blank=True) | |
| 82 | - keywords = models.TextField(blank=True) | |
| 83 | - collaborators = models.TextField(blank=True) | |
| 84 | - created = models.DateTimeField(blank=True, null=True) | |
| 85 | - modified = models.DateTimeField(blank=True, null=True) | |
| 86 | - modified_by = models.TextField(blank=True) | |
| 87 | - | |
| 88 | - class Meta: | |
| 89 | - managed = False | |
| 90 | - db_table = 'ticket_view' | |
| 91 | - | |
| 92 | - def get_absolute_url(self): | |
| 93 | - return u'/ticket/{}'.format(self.id) | |
| 94 | - | |
| 95 | - def get_author(self): | |
| 96 | - try: | |
| 97 | - return User.objects.get(username=self.author) | |
| 98 | - except User.DoesNotExist: | |
| 99 | - return None | |
| 100 | - | |
| 101 | - def get_modified_by(self): | |
| 102 | - try: | |
| 103 | - return User.objects.get(username=self.modified_by) | |
| 104 | - except User.DoesNotExist: | |
| 105 | - return None | |
| 106 | - | |
| 107 | -class Wiki(models.Model, HitCounterModelMixin): | |
| 108 | - name = models.TextField(primary_key=True) | |
| 109 | - wiki_text = models.TextField(blank=True) | |
| 110 | - author = models.TextField(blank=True) | |
| 111 | - collaborators = models.TextField(blank=True) | |
| 112 | - created = models.DateTimeField(blank=True, null=True) | |
| 113 | - modified = models.DateTimeField(blank=True, null=True) | |
| 114 | - modified_by = models.TextField(blank=True) | |
| 115 | - | |
| 116 | - class Meta: | |
| 117 | - managed = False | |
| 118 | - db_table = 'wiki_view' | |
| 119 | - | |
| 120 | - def get_absolute_url(self): | |
| 121 | - return u'/wiki/{}'.format(self.name) | |
| 122 | - | |
| 123 | - def get_author(self): | |
| 124 | - try: | |
| 125 | - return User.objects.get(username=self.author) | |
| 126 | - except User.DoesNotExist: | |
| 127 | - return None | |
| 128 | - | |
| 129 | - def get_modified_by(self): | |
| 130 | - try: | |
| 131 | - return User.objects.get(username=self.modified_by) | |
| 132 | - except User.DoesNotExist: | |
| 133 | - return None | |
| 134 | - | |
| 135 | - | |
| 136 | -class WikiCollabCount(models.Model): | |
| 137 | - author = models.TextField(primary_key=True) | |
| 138 | - count = models.IntegerField() | |
| 139 | - | |
| 140 | - class Meta: | |
| 141 | - managed = False | |
| 142 | - db_table = 'wiki_collab_count_view' | |
| 143 | - | |
| 144 | - | |
| 145 | -class TicketCollabCount(models.Model): | |
| 146 | - author = models.TextField(primary_key=True) | |
| 147 | - count = models.IntegerField() | |
| 148 | - | |
| 149 | - class Meta: | |
| 150 | - managed = False | |
| 151 | - db_table = 'ticket_collab_count_view' | |
| 152 | - | |
| 153 | - | |
| 154 | -@receiver(post_save, sender=User) | |
| 155 | -def change_session_attribute_email(sender, instance, **kwargs): | |
| 156 | - cursor = connections['trac'].cursor() | |
| 157 | - | |
| 158 | - cursor.execute(("UPDATE session_attribute SET value=%s " | |
| 159 | - "WHERE name='email' AND sid=%s"), | |
| 160 | - [instance.email, instance.username]) | |
| 161 | - cursor.execute(("UPDATE session_attribute SET value=%s " | |
| 162 | - "WHERE name='name' AND sid=%s"), | |
| 163 | - [instance.get_full_name(), instance.username]) | |
| 164 | - | |
| 165 | - cursor.execute(("INSERT INTO session_attribute " | |
| 166 | - "(sid, authenticated, name, value) " | |
| 167 | - "SELECT %s, '1', 'email', %s WHERE NOT EXISTS " | |
| 168 | - "(SELECT 1 FROM session_attribute WHERE sid=%s " | |
| 169 | - "AND name='email')"), | |
| 170 | - [instance.username, instance.email, instance.username]) | |
| 171 | - | |
| 172 | - cursor.execute(("INSERT INTO session_attribute " | |
| 173 | - "(sid, authenticated, name, value) " | |
| 174 | - "SELECT %s, '1', 'name', %s WHERE NOT EXISTS " | |
| 175 | - "(SELECT 1 FROM session_attribute WHERE sid=%s " | |
| 176 | - "AND name='name')"), | |
| 177 | - [instance.username, instance.get_full_name(), | |
| 178 | - instance.username]) |
src/proxy/views.py
src/search/templates/search/includes/search_filters.html
| ... | ... | @@ -111,30 +111,34 @@ |
| 111 | 111 | <h4>{% trans "Types" %}</h4> |
| 112 | 112 | |
| 113 | 113 | <ul class="unstyled-list"> |
| 114 | - <li> | |
| 115 | - <span class="glyphicon glyphicon-book"></span> | |
| 116 | - <a href="{% append_to_get type='wiki' %}">{% trans "Wiki" %}</a> | |
| 117 | - </li> | |
| 114 | + {% is_trac_enable as is_trac %} | |
| 115 | + | |
| 116 | + {% if is_trac %} | |
| 117 | + <li> | |
| 118 | + <span class="glyphicon glyphicon-book"></span> | |
| 119 | + <a href="{% append_to_get type='wiki' %}">{% trans "Wiki" %}</a> | |
| 120 | + </li> | |
| 121 | + <li> | |
| 122 | + <span class="glyphicon glyphicon-tag"></span> | |
| 123 | + <a href="{% append_to_get type='ticket' %}">{% trans "Ticket" %}</a> | |
| 124 | + </li> | |
| 125 | + <li> | |
| 126 | + <span class="glyphicon glyphicon-align-right"></span> | |
| 127 | + <a href="{% append_to_get type='changeset' %}">{% trans "Changeset" %}</a> | |
| 128 | + </li> | |
| 129 | + <li> | |
| 130 | + <span class="glyphicon glyphicon-user"></span> | |
| 131 | + <a href="{% append_to_get type='user' %}">{% trans "User" %}</a> | |
| 132 | + </li> | |
| 133 | + <li> | |
| 134 | + <span class="glyphicon glyphicon-file"></span> | |
| 135 | + <a href="{% append_to_get type='attachment' %}">{% trans "Attachment" %}</a> | |
| 136 | + </li> | |
| 137 | + {% endif %} | |
| 118 | 138 | <li> |
| 119 | 139 | <span class="glyphicon glyphicon-envelope"></span> |
| 120 | 140 | <a href="{% append_to_get type='thread' %}">{% trans "Discussion" %}</a> |
| 121 | 141 | </li> |
| 122 | - <li> | |
| 123 | - <span class="glyphicon glyphicon-tag"></span> | |
| 124 | - <a href="{% append_to_get type='ticket' %}">{% trans "Ticket" %}</a> | |
| 125 | - </li> | |
| 126 | - <li> | |
| 127 | - <span class="glyphicon glyphicon-align-right"></span> | |
| 128 | - <a href="{% append_to_get type='changeset' %}">{% trans "Changeset" %}</a> | |
| 129 | - </li> | |
| 130 | - <li> | |
| 131 | - <span class="glyphicon glyphicon-user"></span> | |
| 132 | - <a href="{% append_to_get type='user' %}">{% trans "User" %}</a> | |
| 133 | - </li> | |
| 134 | - <li> | |
| 135 | - <span class="glyphicon glyphicon-file"></span> | |
| 136 | - <a href="{% append_to_get type='attachment' %}">{% trans "Attachment" %}</a> | |
| 137 | - </li> | |
| 138 | 142 | </ul> |
| 139 | 143 | {% endif %} |
| 140 | 144 | <hr /> | ... | ... |
src/search/views.py
| ... | ... | @@ -5,7 +5,7 @@ from django.utils.translation import ugettext as _ |
| 5 | 5 | |
| 6 | 6 | from haystack.views import SearchView |
| 7 | 7 | |
| 8 | -from proxy.trac.models import Attachment | |
| 8 | +from proxy.models import Attachment | |
| 9 | 9 | |
| 10 | 10 | |
| 11 | 11 | class ColabSearchView(SearchView): |
| ... | ... | @@ -16,17 +16,6 @@ class ColabSearchView(SearchView): |
| 16 | 16 | ) |
| 17 | 17 | |
| 18 | 18 | types = { |
| 19 | - 'wiki': { | |
| 20 | - 'name': _(u'Wiki'), | |
| 21 | - 'fields': ( | |
| 22 | - ('author', _(u'Author'), self.request.GET.get('author')), | |
| 23 | - ( | |
| 24 | - 'collaborators', | |
| 25 | - _(u'Collaborators'), | |
| 26 | - self.request.GET.get('collaborators'), | |
| 27 | - ), | |
| 28 | - ), | |
| 29 | - }, | |
| 30 | 19 | 'thread': { |
| 31 | 20 | 'name': _(u'Discussion'), |
| 32 | 21 | 'fields': ( |
| ... | ... | @@ -38,7 +27,22 @@ class ColabSearchView(SearchView): |
| 38 | 27 | ), |
| 39 | 28 | ), |
| 40 | 29 | }, |
| 41 | - 'ticket': { | |
| 30 | + } | |
| 31 | + | |
| 32 | + if settings.TRAC_ENABLED: | |
| 33 | + types['wiki'] = { | |
| 34 | + 'name': _(u'Wiki'), | |
| 35 | + 'fields': ( | |
| 36 | + ('author', _(u'Author'), self.request.GET.get('author')), | |
| 37 | + ( | |
| 38 | + 'collaborators', | |
| 39 | + _(u'Collaborators'), | |
| 40 | + self.request.GET.get('collaborators'), | |
| 41 | + ), | |
| 42 | + ), | |
| 43 | + } | |
| 44 | + | |
| 45 | + types['ticket'] = { | |
| 42 | 46 | 'name': _(u'Ticket'), |
| 43 | 47 | 'fields': ( |
| 44 | 48 | ( |
| ... | ... | @@ -79,8 +83,9 @@ class ColabSearchView(SearchView): |
| 79 | 83 | self.request.GET.get('collaborators') |
| 80 | 84 | ), |
| 81 | 85 | ), |
| 82 | - }, | |
| 83 | - 'changeset': { | |
| 86 | + } | |
| 87 | + | |
| 88 | + types['changeset'] = { | |
| 84 | 89 | 'name': _(u'Changeset'), |
| 85 | 90 | 'fields': ( |
| 86 | 91 | ('author', _(u'Author'), self.request.GET.get('author')), |
| ... | ... | @@ -90,8 +95,9 @@ class ColabSearchView(SearchView): |
| 90 | 95 | self.request.GET.get('repository_name'), |
| 91 | 96 | ), |
| 92 | 97 | ) |
| 93 | - }, | |
| 94 | - 'user': { | |
| 98 | + } | |
| 99 | + | |
| 100 | + types['user'] = { | |
| 95 | 101 | 'name': _(u'User'), |
| 96 | 102 | 'fields': ( |
| 97 | 103 | ( |
| ... | ... | @@ -107,8 +113,9 @@ class ColabSearchView(SearchView): |
| 107 | 113 | ), |
| 108 | 114 | ('role', _(u'Role'), self.request.GET.get('role')) |
| 109 | 115 | ), |
| 110 | - }, | |
| 111 | - 'attachment': { | |
| 116 | + } | |
| 117 | + | |
| 118 | + types['attachment'] = { | |
| 112 | 119 | 'name': _(u'Attachment'), |
| 113 | 120 | 'fields': ( |
| 114 | 121 | ( |
| ... | ... | @@ -128,7 +135,6 @@ class ColabSearchView(SearchView): |
| 128 | 135 | ('size', _(u'Size'), self.request.GET.get('size')), |
| 129 | 136 | ) |
| 130 | 137 | } |
| 131 | - } | |
| 132 | 138 | |
| 133 | 139 | try: |
| 134 | 140 | type_chosen = self.form.cleaned_data.get('type') | ... | ... |
src/super_archives/templatetags/superarchives.py
| ... | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | from django import template |
| 3 | 3 | |
| 4 | 4 | from super_archives.utils import url |
| 5 | +from django.conf import settings | |
| 5 | 6 | |
| 6 | 7 | |
| 7 | 8 | register = template.Library() |
| ... | ... | @@ -32,3 +33,7 @@ def pop_from_get(context, **kwargs): |
| 32 | 33 | context['request'].META['QUERY_STRING'], |
| 33 | 34 | **kwargs |
| 34 | 35 | ) |
| 36 | + | |
| 37 | +@register.assignment_tag | |
| 38 | +def is_trac_enable(): | |
| 39 | + return settings.TRAC_ENABLED | |
| 35 | 40 | \ No newline at end of file | ... | ... |