Commit 1e7861daedeaa731a40e293d6ab64ee7cf7dc5a6

Authored by Gust
1 parent 5dcd8f29

Separeted trac migration from colab

src/accounts/search_indexes.py
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 from haystack import indexes 3 from haystack import indexes
4 from django.db.models import Count 4 from django.db.models import Count
5 5
6 -from proxy.models import Revision, Ticket, Wiki 6 +from proxy.trac.models import Revision, Ticket, Wiki
7 from badger.utils import get_users_counters 7 from badger.utils import get_users_counters
8 from .models import User 8 from .models import User
9 9
src/accounts/views.py
@@ -25,7 +25,7 @@ from haystack.query import SearchQuerySet @@ -25,7 +25,7 @@ from haystack.query import SearchQuerySet
25 from super_archives.models import EmailAddress, Message 25 from super_archives.models import EmailAddress, Message
26 from super_archives.utils.email import send_email_lists 26 from super_archives.utils.email import send_email_lists
27 from search.utils import trans 27 from search.utils import trans
28 -from proxy.models import WikiCollabCount, TicketCollabCount 28 +from proxy.trac.models import WikiCollabCount, TicketCollabCount
29 from .forms import (UserCreationForm, ListsForm, UserUpdateForm, 29 from .forms import (UserCreationForm, ListsForm, UserUpdateForm,
30 ChangeXMPPPasswordForm) 30 ChangeXMPPPasswordForm)
31 from .errors import XMPPChangePwdException 31 from .errors import XMPPChangePwdException
src/api/resources.py
@@ -7,7 +7,7 @@ from tastypie.constants import ALL_WITH_RELATIONS, ALL @@ -7,7 +7,7 @@ from tastypie.constants import ALL_WITH_RELATIONS, ALL
7 from tastypie.resources import ModelResource 7 from tastypie.resources import ModelResource
8 8
9 from super_archives.models import Message, EmailAddress 9 from super_archives.models import Message, EmailAddress
10 -from proxy.models import Revision, Ticket, Wiki 10 +from proxy.trac.models import Revision, Ticket, Wiki
11 11
12 12
13 User = get_user_model() 13 User = get_user_model()
src/badger/utils.py
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 2
3 from django.db.models import Count 3 from django.db.models import Count
4 4
5 -from proxy.models import (Revision, Ticket, Wiki, 5 +from proxy.trac.models import (Revision, Ticket, Wiki,
6 WikiCollabCount, TicketCollabCount) 6 WikiCollabCount, TicketCollabCount)
7 from accounts.models import User 7 from accounts.models import User
8 8
src/colab/custom_settings.py
@@ -262,6 +262,9 @@ TRAC_ENABLED = False @@ -262,6 +262,9 @@ TRAC_ENABLED = False
262 if TRAC_ENABLED: 262 if TRAC_ENABLED:
263 from trac_settings import * 263 from trac_settings import *
264 DATABASES['trac'] = TRAC_DATABASE 264 DATABASES['trac'] = TRAC_DATABASE
  265 + INSTALLED_APPS = INSTALLED_APPS + (
  266 + 'proxy.trac',
  267 + )
265 268
266 269
267 ### Feedzilla (planet) 270 ### Feedzilla (planet)
src/home/views.py
@@ -9,7 +9,7 @@ from django.http import HttpResponse, Http404 @@ -9,7 +9,7 @@ from django.http import HttpResponse, Http404
9 from search.utils import trans 9 from search.utils import trans
10 from haystack.query import SearchQuerySet 10 from haystack.query import SearchQuerySet
11 11
12 -from proxy.models import WikiCollabCount, TicketCollabCount 12 +from proxy.trac.models import WikiCollabCount, TicketCollabCount
13 from super_archives.models import Thread 13 from super_archives.models import Thread
14 14
15 15
@@ -28,13 +28,15 @@ def index(request): @@ -28,13 +28,15 @@ def index(request):
28 type=type, 28 type=type,
29 ).count() 29 ).count()
30 30
31 - count_types['ticket'] = sum([  
32 - ticket.count for ticket in TicketCollabCount.objects.all()  
33 - ]) 31 + if settings.TRAC_ENABLED:
  32 + count_types['ticket'] = sum([
  33 + ticket.count for ticket in TicketCollabCount.objects.all()
  34 + ])
34 35
35 - count_types['wiki'] = sum([  
36 - wiki.count for wiki in WikiCollabCount.objects.all()  
37 - ]) 36 + count_types['wiki'] = sum([
  37 + wiki.count for wiki in WikiCollabCount.objects.all()
  38 + ])
  39 +
38 cache.set('home_chart', count_types) 40 cache.set('home_chart', count_types)
39 41
40 for key in count_types.keys(): 42 for key in count_types.keys():
src/proxy/migrations/0001_initial.py
@@ -1,248 +0,0 @@ @@ -1,248 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -import datetime  
3 -from django.db import connections  
4 -from south.db import db  
5 -from south.v2 import SchemaMigration  
6 -from django.db import models  
7 -  
8 -  
9 -class Migration(SchemaMigration):  
10 -  
11 - def forwards(self, orm):  
12 - connection = connections['trac']  
13 -  
14 - cursor = connection.cursor()  
15 - cursor.execute('''  
16 - CREATE OR REPLACE VIEW wiki_view AS SELECT  
17 - wiki.name AS name,  
18 - (SELECT wiki2.text FROM wiki AS wiki2 WHERE wiki2.name = wiki.name  
19 - AND wiki2.version = MAX(wiki.version)) AS wiki_text,  
20 - (SELECT wiki3.author FROM wiki AS wiki3 WHERE wiki3.name = wiki.name  
21 - AND wiki3.version = 1) AS author,  
22 - string_agg(DISTINCT wiki.author, ', ') AS collaborators,  
23 - TIMESTAMP WITH TIME ZONE 'epoch' + (MAX(wiki.time)/1000000) * INTERVAL '1s' AS created,  
24 - TIMESTAMP WITH TIME ZONE 'epoch' + (MIN(wiki.time)/1000000) * INTERVAL '1s' AS modified  
25 - FROM wiki  
26 - GROUP BY wiki.name;  
27 -  
28 - CREATE OR REPLACE VIEW ticket_view AS SELECT  
29 - ticket.id AS id,  
30 - ticket.summary as summary,  
31 - ticket.description as description,  
32 - ticket.milestone as milestone,  
33 - ticket.priority as priority,  
34 - ticket.component as component,  
35 - ticket.version as version,  
36 - ticket.severity as severity,  
37 - ticket.reporter as reporter,  
38 - ticket.reporter as author,  
39 - ticket.status as status,  
40 - ticket.keywords as keywords,  
41 - (SELECT  
42 - string_agg(DISTINCT ticket_change.author, ', ')  
43 - FROM ticket_change WHERE ticket_change.ticket = ticket.id  
44 - GROUP BY ticket_change.ticket) as collaborators,  
45 - TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000000)* INTERVAL '1s' AS created,  
46 - TIMESTAMP WITH TIME ZONE 'epoch' + (changetime/1000000) * INTERVAL '1s' AS modified  
47 - FROM ticket;  
48 -  
49 - CREATE OR REPLACE VIEW revision_view AS SELECT  
50 - revision.rev,  
51 - revision.author,  
52 - revision.message,  
53 - repository.value AS repository_name,  
54 - TIMESTAMP WITH TIME ZONE 'epoch' + (revision.time/1000000) * INTERVAL '1s' AS created  
55 - FROM revision  
56 - INNER JOIN repository ON(  
57 - repository.id = revision.repos  
58 - AND repository.name = 'name'  
59 - AND repository.value != ''  
60 - );  
61 - ''')  
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 -''')  
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 -''')  
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 -''')  
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;  
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 -''')  
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;  
164 -  
165 -CREATE OR REPLACE VIEW wiki_collab_count_view AS  
166 -SELECT author, count(*) from wiki GROUP BY author;  
167 -''')  
168 -  
169 - pass  
170 -  
171 - def backwards(self, orm):  
172 - connection = connections['trac']  
173 -  
174 - cursor = connection.cursor()  
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;')  
181 -  
182 - pass  
183 -  
184 - models = {  
185 - u'proxy.attachment': {  
186 - 'Meta': {'object_name': 'Attachment', 'db_table': "'attachment_view'", 'managed': 'False'},  
187 - 'attach_id': ('django.db.models.fields.TextField', [], {}),  
188 - 'author': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
189 - 'created': ('django.db.models.fields.DateTimeField', [], {'blank': 'True'}),  
190 - 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
191 - 'filename': ('django.db.models.fields.TextField', [], {}),  
192 - 'mimetype': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
193 - 'size': ('django.db.models.fields.IntegerField', [], {'blank': 'True'}),  
194 - 'url': ('django.db.models.fields.TextField', [], {'primary_key': 'True'}),  
195 - 'used_by': ('django.db.models.fields.TextField', [], {})  
196 - },  
197 - u'proxy.revision': {  
198 - 'Meta': {'object_name': 'Revision', 'db_table': "'revision_view'", 'managed': 'False'},  
199 - 'author': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
200 - 'created': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),  
201 - 'key': ('django.db.models.fields.TextField', [], {'primary_key': 'True'}),  
202 - 'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
203 - 'repository_name': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
204 - 'rev': ('django.db.models.fields.TextField', [], {'blank': 'True'})  
205 - },  
206 - u'proxy.ticket': {  
207 - 'Meta': {'object_name': 'Ticket', 'db_table': "'ticket_view'", 'managed': 'False'},  
208 - 'author': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
209 - 'collaborators': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
210 - 'component': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
211 - 'created': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),  
212 - 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
213 - 'id': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'}),  
214 - 'keywords': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
215 - 'milestone': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
216 - 'modified': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),  
217 - 'modified_by': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
218 - 'priority': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
219 - 'reporter': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
220 - 'severity': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
221 - 'status': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
222 - 'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
223 - 'version': ('django.db.models.fields.TextField', [], {'blank': 'True'})  
224 - },  
225 - u'proxy.ticketcollabcount': {  
226 - 'Meta': {'object_name': 'TicketCollabCount', 'db_table': "'ticket_collab_count_view'", 'managed': 'False'},  
227 - 'author': ('django.db.models.fields.TextField', [], {'primary_key': 'True'}),  
228 - 'count': ('django.db.models.fields.IntegerField', [], {})  
229 - },  
230 - u'proxy.wiki': {  
231 - 'Meta': {'object_name': 'Wiki', 'db_table': "'wiki_view'", 'managed': 'False'},  
232 - 'author': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
233 - 'collaborators': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
234 - 'created': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),  
235 - 'modified': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),  
236 - 'modified_by': ('django.db.models.fields.TextField', [], {'blank': 'True'}),  
237 - 'name': ('django.db.models.fields.TextField', [], {'primary_key': 'True'}),  
238 - 'wiki_text': ('django.db.models.fields.TextField', [], {'blank': 'True'})  
239 - },  
240 - u'proxy.wikicollabcount': {  
241 - 'Meta': {'object_name': 'WikiCollabCount', 'db_table': "'wiki_collab_count_view'", 'managed': 'False'},  
242 - 'author': ('django.db.models.fields.TextField', [], {'primary_key': 'True'}),  
243 - 'count': ('django.db.models.fields.IntegerField', [], {})  
244 - }  
245 - }  
246 -  
247 - complete_apps = ['proxy']  
248 - symmetrical = True  
src/proxy/migrations/__init__.py
src/proxy/models.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -  
3 -import os  
4 -import urllib2  
5 - 2 +from django.db import models
6 from django.conf import settings 3 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 -  
108 -class Wiki(models.Model, HitCounterModelMixin):  
109 - name = models.TextField(primary_key=True)  
110 - wiki_text = models.TextField(blank=True)  
111 - author = models.TextField(blank=True)  
112 - collaborators = models.TextField(blank=True)  
113 - created = models.DateTimeField(blank=True, null=True)  
114 - modified = models.DateTimeField(blank=True, null=True)  
115 - modified_by = models.TextField(blank=True)  
116 -  
117 - class Meta:  
118 - managed = False  
119 - db_table = 'wiki_view'  
120 -  
121 - def get_absolute_url(self):  
122 - return u'/wiki/{}'.format(self.name)  
123 -  
124 - def get_author(self):  
125 - try:  
126 - return User.objects.get(username=self.author)  
127 - except User.DoesNotExist:  
128 - return None  
129 -  
130 - def get_modified_by(self):  
131 - try:  
132 - return User.objects.get(username=self.modified_by)  
133 - except User.DoesNotExist:  
134 - return None  
135 -  
136 -  
137 -class WikiCollabCount(models.Model):  
138 - author = models.TextField(primary_key=True)  
139 - count = models.IntegerField()  
140 -  
141 - class Meta:  
142 - managed = False  
143 - db_table = 'wiki_collab_count_view'  
144 -  
145 -  
146 -class TicketCollabCount(models.Model):  
147 - author = models.TextField(primary_key=True)  
148 - count = models.IntegerField()  
149 -  
150 - class Meta:  
151 - managed = False  
152 - db_table = 'ticket_collab_count_view'  
153 -  
154 -  
155 -@receiver(post_save, sender=User)  
156 -def change_session_attribute_email(sender, instance, **kwargs):  
157 - cursor = connections['trac'].cursor()  
158 -  
159 - cursor.execute(("UPDATE session_attribute SET value=%s "  
160 - "WHERE name='email' AND sid=%s"),  
161 - [instance.email, instance.username])  
162 - cursor.execute(("UPDATE session_attribute SET value=%s "  
163 - "WHERE name='name' AND sid=%s"),  
164 - [instance.get_full_name(), instance.username])  
165 -  
166 - cursor.execute(("INSERT INTO session_attribute "  
167 - "(sid, authenticated, name, value) "  
168 - "SELECT %s, '1', 'email', %s WHERE NOT EXISTS "  
169 - "(SELECT 1 FROM session_attribute WHERE sid=%s "  
170 - "AND name='email')"),  
171 - [instance.username, instance.email, instance.username])  
172 4
173 - cursor.execute(("INSERT INTO session_attribute "  
174 - "(sid, authenticated, name, value) "  
175 - "SELECT %s, '1', 'name', %s WHERE NOT EXISTS "  
176 - "(SELECT 1 FROM session_attribute WHERE sid=%s "  
177 - "AND name='name')"),  
178 - [instance.username, instance.get_full_name(),  
179 - instance.username]) 5 +if settings.TRAC_ENABLED:
  6 + import trac.trac.models
src/proxy/search_indexes.py
@@ -9,7 +9,7 @@ from haystack import indexes @@ -9,7 +9,7 @@ from haystack import indexes
9 from haystack.utils import log as logging 9 from haystack.utils import log as logging
10 10
11 from search.base_indexes import BaseIndex 11 from search.base_indexes import BaseIndex
12 -from .models import Attachment, Ticket, Wiki, Revision 12 +from trac.models import Attachment, Ticket, Wiki, Revision
13 13
14 14
15 logger = logging.getLogger('haystack') 15 logger = logging.getLogger('haystack')
src/proxy/trac/__init__.py 0 → 100644
src/proxy/trac/admin.py 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +from django.contrib import admin
  2 +
  3 +# Register your models here.
src/proxy/trac/migrations/0001_initial.py 0 → 100644
@@ -0,0 +1,248 @@ @@ -0,0 +1,248 @@
  1 +# -*- coding: utf-8 -*-
  2 +import datetime
  3 +from django.db import connections
  4 +from south.db import db
  5 +from south.v2 import SchemaMigration
  6 +from django.db import models
  7 +
  8 +
  9 +class Migration(SchemaMigration):
  10 +
  11 + def forwards(self, orm):
  12 + connection = connections['trac']
  13 +
  14 + cursor = connection.cursor()
  15 + cursor.execute('''
  16 + CREATE OR REPLACE VIEW wiki_view AS SELECT
  17 + wiki.name AS name,
  18 + (SELECT wiki2.text FROM wiki AS wiki2 WHERE wiki2.name = wiki.name
  19 + AND wiki2.version = MAX(wiki.version)) AS wiki_text,
  20 + (SELECT wiki3.author FROM wiki AS wiki3 WHERE wiki3.name = wiki.name
  21 + AND wiki3.version = 1) AS author,
  22 + string_agg(DISTINCT wiki.author, ', ') AS collaborators,
  23 + TIMESTAMP WITH TIME ZONE 'epoch' + (MAX(wiki.time)/1000000) * INTERVAL '1s' AS created,
  24 + TIMESTAMP WITH TIME ZONE 'epoch' + (MIN(wiki.time)/1000000) * INTERVAL '1s' AS modified
  25 + FROM wiki
  26 + GROUP BY wiki.name;
  27 +
  28 + CREATE OR REPLACE VIEW ticket_view AS SELECT
  29 + ticket.id AS id,
  30 + ticket.summary as summary,
  31 + ticket.description as description,
  32 + ticket.milestone as milestone,
  33 + ticket.priority as priority,
  34 + ticket.component as component,
  35 + ticket.version as version,
  36 + ticket.severity as severity,
  37 + ticket.reporter as reporter,
  38 + ticket.reporter as author,
  39 + ticket.status as status,
  40 + ticket.keywords as keywords,
  41 + (SELECT
  42 + string_agg(DISTINCT ticket_change.author, ', ')
  43 + FROM ticket_change WHERE ticket_change.ticket = ticket.id
  44 + GROUP BY ticket_change.ticket) as collaborators,
  45 + TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000000)* INTERVAL '1s' AS created,
  46 + TIMESTAMP WITH TIME ZONE 'epoch' + (changetime/1000000) * INTERVAL '1s' AS modified
  47 + FROM ticket;
  48 +
  49 + CREATE OR REPLACE VIEW revision_view AS SELECT
  50 + revision.rev,
  51 + revision.author,
  52 + revision.message,
  53 + repository.value AS repository_name,
  54 + TIMESTAMP WITH TIME ZONE 'epoch' + (revision.time/1000000) * INTERVAL '1s' AS created
  55 + FROM revision
  56 + INNER JOIN repository ON(
  57 + repository.id = revision.repos
  58 + AND repository.name = 'name'
  59 + AND repository.value != ''
  60 + );
  61 + ''')
  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 +''')
  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 +''')
  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 +''')
  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;
  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 +''')
  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;
  164 +
  165 +CREATE OR REPLACE VIEW wiki_collab_count_view AS
  166 +SELECT author, count(*) from wiki GROUP BY author;
  167 +''')
  168 +
  169 + pass
  170 +
  171 + def backwards(self, orm):
  172 + connection = connections['trac']
  173 +
  174 + cursor = connection.cursor()
  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;')
  181 +
  182 + pass
  183 +
  184 + models = {
  185 + u'proxy.attachment': {
  186 + 'Meta': {'object_name': 'Attachment', 'db_table': "'attachment_view'", 'managed': 'False'},
  187 + 'attach_id': ('django.db.models.fields.TextField', [], {}),
  188 + 'author': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  189 + 'created': ('django.db.models.fields.DateTimeField', [], {'blank': 'True'}),
  190 + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  191 + 'filename': ('django.db.models.fields.TextField', [], {}),
  192 + 'mimetype': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  193 + 'size': ('django.db.models.fields.IntegerField', [], {'blank': 'True'}),
  194 + 'url': ('django.db.models.fields.TextField', [], {'primary_key': 'True'}),
  195 + 'used_by': ('django.db.models.fields.TextField', [], {})
  196 + },
  197 + u'proxy.revision': {
  198 + 'Meta': {'object_name': 'Revision', 'db_table': "'revision_view'", 'managed': 'False'},
  199 + 'author': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  200 + 'created': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
  201 + 'key': ('django.db.models.fields.TextField', [], {'primary_key': 'True'}),
  202 + 'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  203 + 'repository_name': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  204 + 'rev': ('django.db.models.fields.TextField', [], {'blank': 'True'})
  205 + },
  206 + u'proxy.ticket': {
  207 + 'Meta': {'object_name': 'Ticket', 'db_table': "'ticket_view'", 'managed': 'False'},
  208 + 'author': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  209 + 'collaborators': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  210 + 'component': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  211 + 'created': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
  212 + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  213 + 'id': ('django.db.models.fields.IntegerField', [], {'primary_key': 'True'}),
  214 + 'keywords': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  215 + 'milestone': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  216 + 'modified': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
  217 + 'modified_by': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  218 + 'priority': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  219 + 'reporter': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  220 + 'severity': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  221 + 'status': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  222 + 'summary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  223 + 'version': ('django.db.models.fields.TextField', [], {'blank': 'True'})
  224 + },
  225 + u'proxy.ticketcollabcount': {
  226 + 'Meta': {'object_name': 'TicketCollabCount', 'db_table': "'ticket_collab_count_view'", 'managed': 'False'},
  227 + 'author': ('django.db.models.fields.TextField', [], {'primary_key': 'True'}),
  228 + 'count': ('django.db.models.fields.IntegerField', [], {})
  229 + },
  230 + u'proxy.wiki': {
  231 + 'Meta': {'object_name': 'Wiki', 'db_table': "'wiki_view'", 'managed': 'False'},
  232 + 'author': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  233 + 'collaborators': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  234 + 'created': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
  235 + 'modified': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
  236 + 'modified_by': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
  237 + 'name': ('django.db.models.fields.TextField', [], {'primary_key': 'True'}),
  238 + 'wiki_text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
  239 + },
  240 + u'proxy.wikicollabcount': {
  241 + 'Meta': {'object_name': 'WikiCollabCount', 'db_table': "'wiki_collab_count_view'", 'managed': 'False'},
  242 + 'author': ('django.db.models.fields.TextField', [], {'primary_key': 'True'}),
  243 + 'count': ('django.db.models.fields.IntegerField', [], {})
  244 + }
  245 + }
  246 +
  247 + complete_apps = ['proxy']
  248 + symmetrical = True
src/proxy/trac/migrations/__init__.py 0 → 100644
src/proxy/trac/models.py 0 → 100644
@@ -0,0 +1,178 @@ @@ -0,0 +1,178 @@
  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/trac/tests.py 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +from django.test import TestCase
  2 +
  3 +# Create your tests here.
src/proxy/trac/views.py 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +from django.shortcuts import render
  2 +
  3 +# Create your views here.
src/proxy/views.py
@@ -4,7 +4,7 @@ import os @@ -4,7 +4,7 @@ import os
4 from django.conf import settings 4 from django.conf import settings
5 5
6 from revproxy.views import ProxyView 6 from revproxy.views import ProxyView
7 -from .models import Wiki, Ticket, Revision 7 +from trac.models import Wiki, Ticket, Revision
8 from hitcounter.views import HitCounterViewMixin 8 from hitcounter.views import HitCounterViewMixin
9 9
10 10
src/search/views.py
@@ -5,7 +5,7 @@ from django.utils.translation import ugettext as _ @@ -5,7 +5,7 @@ from django.utils.translation import ugettext as _
5 5
6 from haystack.views import SearchView 6 from haystack.views import SearchView
7 7
8 -from proxy.models import Attachment 8 +from proxy.trac.models import Attachment
9 9
10 10
11 class ColabSearchView(SearchView): 11 class ColabSearchView(SearchView):