Merge Request #36

Closed
softwarepublico/colab!36
Created by Carolina

Trac indexing

Milestone: None

Closed by Alexandre Barbosa

Changes were not merged into target branch

Commits (34)
7 participants
ci/install_solr.sh
... ... @@ -8,14 +8,14 @@ download() {
8 8 FILE="$2.tgz"
9 9 if [ -f $FILE ];
10 10 then
11   - echo "File $FILE exists."
12   - tar -zxf $FILE
  11 + echo "File $FILE exists."
  12 + tar -zxf $FILE
13 13 else
14   - echo "Downloading solr from $1..."
15   - curl -O $1
16   - tar -zxf $FILE
  14 + echo "File $FILE does not exist. Downloading solr from $1..."
  15 + curl -O $1
  16 + tar -zxf $FILE
17 17 fi
18   - echo "Downloaded"
  18 + echo "Downloaded!"
19 19 }
20 20  
21 21 is_solr_up(){
... ... @@ -183,11 +183,7 @@ download_and_run() {
183 183 # copies custom configurations
184 184 for file in $SOLR_CONFS
185 185 do
186   - if [ -d $file ]
187   - then
188   - cp $file/* $dir_name/example/solr/$dir_conf
189   - echo "Copied directory $file into solr conf directory."
190   - elif [ -f $file ]
  186 + if [ -f $file ]
191 187 then
192 188 cp $file $dir_name/example/solr/$dir_conf
193 189 echo "Copied $file into solr conf directory."
... ...
colab/proxy/trac/data_api.py
  1 +# -*- coding: utf-8 -*-
  2 +from re import match
  3 +
  4 +from django.db import connections
  5 +
  6 +from colab.proxy.trac.models import Attachment, Revision, Ticket, Wiki
1 7 from colab.proxy.utils.proxy_data_api import ProxyDataAPI
2 8  
3 9  
4 10 class TracDataAPI(ProxyDataAPI):
5 11  
6 12 def fetch_data(self):
7   - pass
  13 + """ This is the pricipal method whose function is just make the call the
  14 + other methods.
  15 +
  16 + """
  17 + connection = connections['trac']
  18 + cursor = connection.cursor()
  19 + self.fetch_data_wiki(cursor)
  20 + self.fetch_data_attachment(cursor)
  21 + self.fetch_data_ticket(cursor)
  22 + self.fetch_data_revision(cursor)
  23 +
  24 + def fetch_data_attachment(self, empty_cursor):
  25 + """ This method is responsible for seeking the attachment data in
  26 +        trac database and transfer them to the colab database.
  27 +
  28 + :param empty_cursor: A cursor coming from connectinos, it is necessary
  29 +         import the connections library from django.db, with it we can run
  30 +         sql commands.
  31 +
  32 +        :returns: Return is an attachment object with your saved data
  33 +         in the colab database.
  34 +
  35 + """
  36 + attachment = Attachment()
  37 + cursor = self.attachment_cursor(empty_cursor)
  38 + attachment_dict = self.dictfetchall(cursor)
  39 + for line in attachment_dict:
  40 + attachment.description = line['description']
  41 + attachment.id = line['id']
  42 + attachment.filename = line['filename']
  43 + attachment.title = attachment.filename
  44 + attachment.size = line['size']
  45 + attachment.author = line['author']
  46 + attachment.used_by = line['type']
  47 + attachment.ipnr = line['ipnr']
  48 + attachment.url = attachment.used_by + "/" + attachment.id \
  49 + + "/" + attachment.filename
  50 + attachment.created = self.get_attachment_created(cursor,
  51 + line['id'])
  52 + if match("\.(\w+)$", attachment.filename):
  53 + attachment.mimetype = attachment.filename.lower()
  54 + attachment.save()
  55 +
  56 + def fetch_data_revision(self, empty_cursor):
  57 + """ This method is responsible for seeking the revision data in
  58 +        trac database and transfer them to the colab database.
  59 +
  60 +        :param empty_cursor: A cursor coming from connectinos, it is necessary
  61 +       import the connections library from django.db, with it we can run
  62 +         sql commands.
  63 +
  64 +        :returns: Return is an revision object with your saved data
  65 +         in the colab database.
  66 +
  67 + """
  68 + revision = Revision()
  69 + cursor = self.revision_cursor(empty_cursor)
  70 + revision_dict = self.dictfetchall(cursor)
  71 + cursor = self.repository_cursor(empty_cursor)
  72 + repository_dict = self.dictfetchall(cursor)
  73 + for line in revision_dict:
  74 + revision.author = line['author']
  75 + revision.rev = line['rev']
  76 + revision.message = line['message']
  77 + revision.description = revision.message
  78 + revision.created = self.get_revision_created(cursor, line['rev'])
  79 + revision.repository_name = line['repos']
  80 + revision.save()
  81 +
  82 + def fetch_data_ticket(self, empty_cursor):
  83 + """ This method is responsible for seeking the ticket data in
  84 +        trac database and transfer them to the colab database.
  85 +
  86 +        :param empty_cursor: A cursor coming from connectinos, it is necessary
  87 +         import the connections library from django.db, with it we can run
  88 +         sql commands.
  89 +
  90 +        :returns: Return is an ticker object with your saved data
  91 +         in the colab database.
  92 +
  93 + """
  94 + ticket = Ticket()
  95 + collaborators = []
  96 + cursor = self.ticket_cursor(empty_cursor)
  97 + ticket_dict = self.dictfetchall(cursor)
  98 + for line in ticket_dict:
  99 + ticket.id = line['id']
  100 + ticket.summary = line['summary']
  101 + ticket.description_ticket = line['description']
  102 + ticket.milestone = line['milestone']
  103 + ticket.priority = line['priority']
  104 + ticket.component = line['component']
  105 + ticket.version = line['version']
  106 + ticket.severity = line['severity']
  107 + ticket.reporter = line['reporter']
  108 + ticket.status = line['status']
  109 + ticket.tag = ticket.status
  110 + if line['keywords']:
  111 + ticket.keywords = line['keywords']
  112 + if line['owner']:
  113 + ticket.owner = line['owner']
  114 + else:
  115 + ticket.owner = 'Anonymous'
  116 + if line['resolution']:
  117 + ticket.resolution = line['resolution']
  118 + else:
  119 + ticket.resolution = 'no resolution'
  120 + ticket.author = ticket.reporter
  121 + ticket.created = self.get_ticket_created(cursor, line['id'])
  122 + ticket.modified = self.get_ticket_modified(cursor, line['id'])
  123 + if line['reporter'] not in collaborators:
  124 + collaborators.append(line['reporter'])
  125 + ticket.collaborators = collaborators
  126 + ticket.update_user(ticket.author)
  127 + ticket.save()
  128 +
  129 + def fetch_data_wiki(self, empty_cursor):
  130 + """ This method is responsible for seeking the wiki data in
  131 +        trac database and transfer them to the colab database.
  132 +
  133 +        :param empty_cursor: A cursor coming from connectinos, it is necessary
  134 +         import the connections library from django.db, with it we can run
  135 +         sql commands.
  136 +
  137 +        :returns: Return is an wiki object with your saved data
  138 +         in the colab database.
  139 +
  140 + """
  141 + wiki = Wiki()
  142 + cursor = self.wiki_cursor(empty_cursor)
  143 + wiki_dict = self.dictfetchall(cursor)
  144 + collaborators = []
  145 + for line in wiki_dict:
  146 + wiki.update_user(line['author'])
  147 + wiki.title = line['name']
  148 + wiki.wiki_text = line['text']
  149 + wiki.author = line['author']
  150 + if line['author'] not in collaborators:
  151 + collaborators.append(line['author'])
  152 + wiki.collaborators = collaborators
  153 + wiki.created = self.get_wiki_created(cursor, line['name'])
  154 + wiki.modified = self.get_wiki_modified(cursor, line['name'])
  155 +
  156 + wiki.save()
  157 +
  158 + def dictfetchall(self, cursor):
  159 + """ This method is responsible for taking the cursor content
  160 +        and turn it into a dictionary.
  161 +
  162 +        The cursor returns an array of tuples, With this method it will return
  163 + a list of dictionaries..
  164 +
  165 +        :param cursor: A cursor coming from connections, it is necessary
  166 +         import the connections from library django.db, with it we can run
  167 +         sql commands.
  168 +
  169 +        :returns: Return are cursor.fetchall() in the format of dictionary
  170 +
  171 + """
  172 + desc = cursor.description
  173 + return [
  174 + dict(zip([col[0] for col in desc], row))
  175 + for row in cursor.fetchall()
  176 + ]
  177 +
  178 + def wiki_cursor(self, cursor):
  179 + """ This is the method in charge of getting the wiki table data and
  180 +        put them in the cursor.
  181 +
  182 +        :param cursor: A cursor coming from connections, it is necessary
  183 +         import the connections from library django.db, with it we can run
  184 +         sql commands.
  185 +
  186 +        :returns: The return is the result of the desired query
  187 +
  188 + """
  189 + cursor.execute('''SELECT * FROM wiki;''')
  190 + return cursor
  191 +
  192 + def attachment_cursor(self, cursor):
  193 + """ This is the method in charge of getting the attachment table data and
  194 +        put them in the cursor.
  195 +
  196 +        :param cursor: A cursor coming from connections, it is necessary
  197 +         import the connections from library django.db, with it we can run
  198 +         sql commands.
  199 +
  200 +        :returns: The return is the result of the desired query
  201 +
  202 + """
  203 + cursor.execute('''SELECT * FROM attachment;''')
  204 + return cursor
  205 +
  206 + def ticket_cursor(self, cursor):
  207 + """ This is the method in charge of getting the ticket table data and
  208 +        put them in the cursor.
  209 +
  210 +        :param cursor: A cursor coming from connections, it is necessary
  211 +         import the connections from library django.db, with it we can run
  212 +         sql commands.
  213 +
  214 +        :returns: The return is the result of the desired query
  215 +
  216 + """
  217 + cursor.execute('''SELECT * FROM ticket;''')
  218 + return cursor
  219 +
  220 + def revision_cursor(self, cursor):
  221 + """ This is the method in charge of getting the revision table data and
  222 +        put them in the cursor.
  223 +
  224 +        :param cursor: A cursor coming from connections, it is necessary
  225 +         import the connections from library django.db, with it we can run
  226 +         sql commands.
  227 +
  228 +        :returns: The return is the result of the desired query
  229 +
  230 + """
  231 + cursor.execute('''SELECT * FROM revision;''')
  232 + return cursor
  233 +
  234 + def repository_cursor(self, cursor):
  235 + """ This is the method in charge of getting the repository table data and
  236 +        put them in the cursor.
  237 +
  238 +        :param cursor: A cursor coming from connections, it is necessary
  239 +         import the connections from library django.db, with it we can run
  240 +         sql commands.
  241 +
  242 +        :returns: The return is the result of the desired query
  243 +
  244 + """
  245 + cursor.execute('''SELECT * FROM repository;''')
  246 + return cursor
  247 +
  248 + def get_wiki_modified(self, cursor, wiki_name):
  249 + """ This is the method in charge of getting the datetime in the wiki was
  250 +        modified and put it in GMT format.
  251 +
  252 +        :param cursor: A cursor coming from connections, it is necessary
  253 +         import the connections from library django.db, with it we can run
  254 +         sql commands.
  255 +
  256 +        :param wiki_name: is the name of the current wiki.
  257 +
  258 +        :returns: The return is the result of the desired query
  259 +
  260 + """
  261 + cursor.execute("""SELECT TIMESTAMP WITH TIME ZONE 'epoch' + \
  262 + (MAX(wiki.time)/1000000) * INTERVAL '1s', \
  263 + name from wiki where(name=\'""" + wiki_name + """\') \
  264 + group by name; """)
  265 + matriz_data_wiki = cursor.fetchall()
  266 + modified_data = matriz_data_wiki[0][0]
  267 + return modified_data
  268 +
  269 + def get_wiki_created(self, cursor, wiki_name):
  270 + """ This is the method in charge of getting the datetime in the wiki was
  271 +        created and put it in GMT format.
  272 +
  273 +        :param cursor: A cursor coming from connections, it is necessary
  274 +         import the connections from library django.db, with it we can run
  275 +         sql commands.
  276 +
  277 +        :param wiki_name: is the name of the current wiki.
  278 +
  279 +        :returns: The return is the result of the desired query
  280 +
  281 + """
  282 + cursor.execute("""SELECT TIMESTAMP WITH TIME ZONE 'epoch' + \
  283 + (MIN(wiki.time)/1000000) * INTERVAL '1s', \
  284 + name from wiki where(name=\'""" + wiki_name + """\') \
  285 + group by name; """)
  286 + matriz_data_wiki = cursor.fetchall()
  287 + modified_data = matriz_data_wiki[0][0]
  288 + return modified_data
  289 +
  290 + def get_attachment_created(self, cursor, attachment_id):
  291 + """ This is the method in charge of getting the datetime in the
  292 + attachment was created and put it in GMT format.
  293 +
  294 +        :param cursor: A cursor coming from connections, it is necessary
  295 +         import the connections from library django.db, with it we can run
  296 +         sql commands.
  297 +
  298 +        :param attachment_id: is the id of the current attachment.
  299 +
  300 +        :returns: The return is the result of the desired query
  301 +
  302 + """
  303 + cursor.execute("""SELECT TIMESTAMP WITH TIME ZONE 'epoch' + \
  304 + (MIN(attachment.time)/1000000) * INTERVAL '1s', \
  305 + id from attachment \
  306 + where(id=\'""" + attachment_id + """\') \
  307 + group by id; """)
  308 + matriz_data_attachment = cursor.fetchall()
  309 + modified_data = matriz_data_attachment[0][0]
  310 + return modified_data
  311 +
  312 + def get_revision_created(self, cursor, revision):
  313 + """ This is the method in charge of getting the datetime in the revision
  314 + was modified and put it in GMT format.
  315 +
  316 +        :param cursor: A cursor coming from connections, it is necessary
  317 +         import the connections from library django.db, with it we can run
  318 +         sql commands.
  319 +
  320 +        :param revision: is the current revision.
  321 +
  322 +        :returns: The return is the result of the desired query
  323 +
  324 + """
  325 + cursor.execute("""SELECT TIMESTAMP WITH TIME ZONE 'epoch' + \
  326 + (MIN(revision.time)/1000000) * INTERVAL '1s', \
  327 + rev from revision where(rev=\'""" + revision + """\') \
  328 + group by rev; """)
  329 + matriz_data_revision = cursor.fetchall()
  330 + modified_data = matriz_data_revision[0][0]
  331 + return modified_data
  332 +
  333 + def get_ticket_created(self, cursor, ticket_id):
  334 + """ This is the method in charge of getting the datetime in the ticket
  335 + was created and put it in GMT format.
  336 +
  337 +        :param cursor: A cursor coming from connections, it is necessary
  338 +         import the connections from library django.db, with it we can run
  339 +         sql commands.
  340 +
  341 +        :param ticket_id: is the id of the current ticket.
  342 +
  343 +        :returns: The return is the result of the desired query
  344 +
  345 + """
  346 + cursor.execute("""SELECT TIMESTAMP WITH TIME ZONE 'epoch' + \
  347 + (MIN(ticket.time)/1000000) * INTERVAL '1s', \
  348 + id from ticket where(id=""" + str(ticket_id) + """) \
  349 + group by id; """)
  350 + matriz_data_ticket = cursor.fetchall()
  351 + modified_data = matriz_data_ticket[0][0]
  352 + return modified_data
  353 +
  354 + def get_ticket_modified(self, cursor, ticket_id):
  355 + """ This is the method in charge of getting the datetime in the ticket
  356 + was modified and put it in GMT format.
  357 +
  358 +        :param cursor: A cursor coming from connections, it is necessary
  359 +         import the connections from library django.db, with it we can run
  360 +         sql commands.
  361 +
  362 +        :param ticket_id: is the id of the current ticket.
  363 +
  364 +        :returns: The return is the result of the desired query
  365 + """
  366 + cursor.execute("""SELECT TIMESTAMP WITH TIME ZONE 'epoch' + \
  367 + (MAX(ticket.time)/1000000) * INTERVAL '1s', \
  368 + id from ticket where(id=""" + str(ticket_id) + """) \
  369 + group by id; """)
  370 + matriz_data_ticket = cursor.fetchall()
  371 + modified_data = matriz_data_ticket[0][0]
  372 + return modified_data
... ...
colab/proxy/trac/fixtures/__init__.py
colab/proxy/trac/fixtures/trac_data.json
... ... @@ -0,0 +1 @@
  1 +[{"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.058Z", "user": null}, "model": "trac.wiki", "pk": "CamelCase"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.010Z", "user": null}, "model": "trac.wiki", "pk": "InterMapTxt"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.023Z", "user": null}, "model": "trac.wiki", "pk": "InterTrac"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.017Z", "user": null}, "model": "trac.wiki", "pk": "InterWiki"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.040Z", "user": null}, "model": "trac.wiki", "pk": "PageTemplates"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.122Z", "user": null}, "model": "trac.wiki", "pk": "RecentChanges"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.061Z", "user": null}, "model": "trac.wiki", "pk": "SandBox"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.033Z", "user": null}, "model": "trac.wiki", "pk": "TitleIndex"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.142Z", "user": null}, "model": "trac.wiki", "pk": "TracAccessibility"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.174Z", "user": null}, "model": "trac.wiki", "pk": "TracAdmin"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.206Z", "user": null}, "model": "trac.wiki", "pk": "TracBackup"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.030Z", "user": null}, "model": "trac.wiki", "pk": "TracBatchModify"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.097Z", "user": null}, "model": "trac.wiki", "pk": "TracBrowser"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.050Z", "user": null}, "model": "trac.wiki", "pk": "TracCgi"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.177Z", "user": null}, "model": "trac.wiki", "pk": "TracChangeset"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.046Z", "user": null}, "model": "trac.wiki", "pk": "TracEnvironment"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.196Z", "user": null}, "model": "trac.wiki", "pk": "TracFastCgi"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.190Z", "user": null}, "model": "trac.wiki", "pk": "TracFineGrainedPermissions"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.116Z", "user": null}, "model": "trac.wiki", "pk": "TracGuide"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.100Z", "user": null}, "model": "trac.wiki", "pk": "TracImport"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.180Z", "user": null}, "model": "trac.wiki", "pk": "TracIni"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.087Z", "user": null}, "model": "trac.wiki", "pk": "TracInstall"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.037Z", "user": null}, "model": "trac.wiki", "pk": "TracInterfaceCustomization"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.139Z", "user": null}, "model": "trac.wiki", "pk": "TracLinks"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.020Z", "user": null}, "model": "trac.wiki", "pk": "TracLogging"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.126Z", "user": null}, "model": "trac.wiki", "pk": "TracModPython"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.135Z", "user": null}, "model": "trac.wiki", "pk": "TracModWSGI"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.027Z", "user": null}, "model": "trac.wiki", "pk": "TracNavigation"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.145Z", "user": null}, "model": "trac.wiki", "pk": "TracNotification"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.170Z", "user": null}, "model": "trac.wiki", "pk": "TracPermissions"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.164Z", "user": null}, "model": "trac.wiki", "pk": "TracPlugins"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.119Z", "user": null}, "model": "trac.wiki", "pk": "TracQuery"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.129Z", "user": null}, "model": "trac.wiki", "pk": "TracReports"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.084Z", "user": null}, "model": "trac.wiki", "pk": "TracRepositoryAdmin"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.158Z", "user": null}, "model": "trac.wiki", "pk": "TracRevisionLog"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.183Z", "user": null}, "model": "trac.wiki", "pk": "TracRoadmap"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.154Z", "user": null}, "model": "trac.wiki", "pk": "TracRss"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.067Z", "user": null}, "model": "trac.wiki", "pk": "TracSearch"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.064Z", "user": null}, "model": "trac.wiki", "pk": "TracStandalone"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.151Z", "user": null}, "model": "trac.wiki", "pk": "TracSupport"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.076Z", "user": null}, "model": "trac.wiki", "pk": "TracSyntaxColoring"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.113Z", "user": null}, "model": "trac.wiki", "pk": "TracTickets"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.203Z", "user": null}, "model": "trac.wiki", "pk": "TracTicketsCustomFields"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.071Z", "user": null}, "model": "trac.wiki", "pk": "TracTimeline"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:22Z", "modified": "2015-02-11T16:13:15.054Z", "user": null}, "model": "trac.wiki", "pk": "TracUnicode"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.193Z", "user": null}, "model": "trac.wiki", "pk": "TracUpgrade"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.132Z", "user": null}, "model": "trac.wiki", "pk": "TracWiki"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.080Z", "user": null}, "model": "trac.wiki", "pk": "TracWorkflow"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.110Z", "user": null}, "model": "trac.wiki", "pk": "WikiDeletePage"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.167Z", "user": null}, "model": "trac.wiki", "pk": "WikiFormatting"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.200Z", "user": null}, "model": "trac.wiki", "pk": "WikiHtml"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.107Z", "user": null}, "model": "trac.wiki", "pk": "WikiMacros"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.103Z", "user": null}, "model": "trac.wiki", "pk": "WikiNewPage"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.161Z", "user": null}, "model": "trac.wiki", "pk": "WikiPageNames"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.090Z", "user": null}, "model": "trac.wiki", "pk": "WikiProcessors"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.187Z", "user": null}, "model": "trac.wiki", "pk": "WikiRestructuredText"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.094Z", "user": null}, "model": "trac.wiki", "pk": "WikiRestructuredTextLinks"}, {"fields": {"collaborators": "[u'trac']", "author": "trac", "wiki_text": "", "created": "2015-02-09T19:57:23Z", "modified": "2015-02-11T16:13:15.148Z", "user": null}, "model": "trac.wiki", "pk": "WikiStart"}]
0 2 \ No newline at end of file
... ...
colab/proxy/trac/migrations/0001_initial.py
1 1 # -*- coding: utf-8 -*-
2 2 from __future__ import unicode_literals
3 3  
4   -from django.db import models, migrations, connections
5   -
6   -
7   -def create_views(apps, schema_editor):
8   - connection = connections['trac']
9   -
10   - cursor = connection.cursor()
11   -
12   - # revision_view
13   - cursor.execute('''
14   - CREATE OR REPLACE VIEW revision_view AS SELECT
15   - revision.rev,
16   - revision.author,
17   - revision.message,
18   - repository.value AS repository_name,
19   - TIMESTAMP WITH TIME ZONE 'epoch' + (revision.time/1000000) * INTERVAL '1s' AS created,
20   - CONCAT(revision.repos, '-', revision.rev) AS key
21   - FROM revision
22   - INNER JOIN repository ON(
23   - repository.id = revision.repos
24   - AND repository.name = 'name'
25   - AND repository.value != ''
26   - );
27   - ''')
28   -
29   - # attachment_view
30   - cursor.execute('''
31   - CREATE OR REPLACE VIEW attachment_view AS SELECT
32   - CONCAT(attachment.type, '/' , attachment.id, '/', attachment.filename) AS url,
33   - attachment.type AS used_by,
34   - attachment.filename AS filename,
35   - attachment.id as attach_id,
36   - (SELECT LOWER(SUBSTRING(attachment.filename FROM '\.(\w+)$'))) AS mimetype,
37   - attachment.author AS author,
38   - attachment.description AS description,
39   - attachment.size AS size,
40   - TIMESTAMP WITH TIME ZONE 'epoch' + (attachment.time/1000000)* INTERVAL '1s' AS created
41   - FROM attachment;
42   - ''')
43   -
44   - # wiki_view
45   - cursor.execute('''
46   - CREATE OR REPLACE VIEW wiki_view AS SELECT
47   - wiki.name AS name,
48   - (SELECT wiki2.text FROM wiki AS wiki2 WHERE wiki2.name = wiki.name
49   - AND wiki2.version = MAX(wiki.version)) AS wiki_text,
50   - (SELECT wiki3.author FROM wiki AS wiki3 WHERE wiki3.name = wiki.name
51   - AND wiki3.version = 1) AS author,
52   - string_agg(DISTINCT wiki.author, ', ') AS collaborators,
53   - TIMESTAMP WITH TIME ZONE 'epoch' + (MIN(wiki.time)/1000000) * INTERVAL '1s' AS created,
54   - TIMESTAMP WITH TIME ZONE 'epoch' + (MAX(wiki.time)/1000000) * INTERVAL '1s' AS modified,
55   - (SELECT wiki4.author FROM wiki AS wiki4 WHERE wiki4.name = wiki.name
56   - AND wiki4.version = MAX(wiki.version)) AS modified_by
57   - FROM wiki
58   - GROUP BY wiki.name;
59   - ''')
60   -
61   - # ticket_view
62   - cursor.execute('''
63   - CREATE OR REPLACE VIEW ticket_view AS SELECT
64   - ticket.id AS id,
65   - ticket.summary as summary,
66   - ticket.description as description,
67   - ticket.milestone as milestone,
68   - ticket.priority as priority,
69   - ticket.component as component,
70   - ticket.version as version,
71   - ticket.severity as severity,
72   - ticket.reporter as reporter,
73   - ticket.reporter as author,
74   - ticket.status as status,
75   - ticket.keywords as keywords,
76   - (SELECT
77   - string_agg(DISTINCT ticket_change.author, ', ')
78   - FROM ticket_change WHERE ticket_change.ticket = ticket.id
79   - GROUP BY ticket_change.ticket) as collaborators,
80   - TIMESTAMP WITH TIME ZONE 'epoch' + (time/1000000)* INTERVAL '1s' AS created,
81   - TIMESTAMP WITH TIME ZONE 'epoch' + (changetime/1000000) * INTERVAL '1s' AS modified,
82   - (SELECT
83   - ticket_change.author
84   - FROM ticket_change
85   - WHERE ticket_change.ticket = ticket.id
86   - AND ticket_change.time = ticket.changetime
87   - LIMIT 1
88   - ) AS modified_by
89   - FROM ticket;
90   - ''')
91   -
92   - # ticket_collab_count_view
93   - cursor.execute('''
94   - CREATE OR REPLACE VIEW ticket_collab_count_view AS
95   - SELECT
96   - COALESCE (t1.author, t2.author) as author,
97   - (COALESCE(t1.count, 0) + COALESCE(t2.count, 0)) as count
98   - FROM
99   - (SELECT author, count(*) as count
100   - FROM ticket_change
101   - GROUP BY author
102   - ORDER BY author
103   - ) AS t1
104   - FULL OUTER JOIN
105   - (SELECT reporter as author, count(*) as count
106   - FROM ticket
107   - GROUP BY reporter
108   - ORDER BY reporter
109   - ) AS t2
110   - ON t1.author = t2.author;
111   - ''')
112   -
113   - # wiki_collab_count_view
114   - cursor.execute('''
115   - CREATE OR REPLACE VIEW wiki_collab_count_view AS
116   - SELECT author, count(*) from wiki GROUP BY author;
117   - ''')
118   -
119   -
120   -def drop_views(apps, schema_editor):
121   - connection = connections['trac']
122   -
123   - cursor = connection.cursor()
124   - cursor.execute('''
125   - DROP VIEW IF EXISTS revision_view;
126   - DROP VIEW IF EXISTS ticket_view;
127   - DROP VIEW IF EXISTS wiki_view;
128   - DROP VIEW IF EXISTS ticket_collab_count_view;
129   - DROP VIEW IF EXISTS wiki_collab_count_view;
130   - DROP VIEW IF EXISTS attachment_view;
131   - ''')
  4 +from django.db import models, migrations
  5 +import django.db.models.deletion
  6 +import hitcounter.models
  7 +from django.conf import settings
132 8  
133 9  
134 10 class Migration(migrations.Migration):
135 11  
136 12 dependencies = [
  13 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
137 14 ]
138 15  
139 16 operations = [
140   - migrations.RunPython(code=create_views, reverse_code=drop_views)
  17 + migrations.CreateModel(
  18 + name='Attachment',
  19 + fields=[
  20 + ('url', models.TextField(serialize=False, primary_key=True)),
  21 + ('attach_id', models.TextField()),
  22 + ('used_by', models.TextField()),
  23 + ('filename', models.TextField()),
  24 + ('author', models.TextField(blank=True)),
  25 + ('title', models.TextField(blank=True)),
  26 + ('description', models.TextField(blank=True)),
  27 + ('modified', models.DateTimeField(blank=True)),
  28 + ('mimetype', models.TextField(blank=True)),
  29 + ('size', models.IntegerField(blank=True)),
  30 + ('ipnr', models.TextField(blank=True)),
  31 + ],
  32 + options={
  33 + 'verbose_name': 'Attachment',
  34 + 'verbose_name_plural': 'Attachment',
  35 + },
  36 + bases=(models.Model, hitcounter.models.HitCounterModelMixin),
  37 + ),
  38 + migrations.CreateModel(
  39 + name='Revision',
  40 + fields=[
  41 + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
  42 + ('rev', models.TextField(blank=True)),
  43 + ('author', models.TextField(blank=True)),
  44 + ('message', models.TextField(blank=True)),
  45 + ('description', models.TextField(blank=True)),
  46 + ('repository_name', models.TextField(blank=True)),
  47 + ('created', models.DateTimeField(null=True, blank=True)),
  48 + ('modified', models.DateTimeField(null=True, blank=True)),
  49 + ],
  50 + options={
  51 + 'verbose_name': 'Revision',
  52 + 'verbose_name_plural': 'Revision',
  53 + },
  54 + bases=(models.Model, hitcounter.models.HitCounterModelMixin),
  55 + ),
  56 + migrations.CreateModel(
  57 + name='Ticket',
  58 + fields=[
  59 + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
  60 + ('summary', models.TextField(blank=True)),
  61 + ('description_ticket', models.TextField(blank=True)),
  62 + ('milestone', models.TextField(blank=True)),
  63 + ('priority', models.TextField(blank=True)),
  64 + ('component', models.TextField(blank=True)),
  65 + ('version', models.TextField(blank=True)),
  66 + ('severity', models.TextField(blank=True)),
  67 + ('reporter', models.TextField(blank=True)),
  68 + ('author', models.TextField(blank=True)),
  69 + ('status', models.TextField(blank=True)),
  70 + ('tag', models.TextField(blank=True)),
  71 + ('keywords', models.TextField(blank=True)),
  72 + ('collaborators', models.TextField(blank=True)),
  73 + ('created', models.DateTimeField(null=True, blank=True)),
  74 + ('modified', models.DateTimeField(null=True, blank=True)),
  75 + ('modified_by', models.TextField(blank=True)),
  76 + ('owner', models.TextField(blank=True)),
  77 + ('resolution', models.TextField(blank=True)),
  78 + ],
  79 + options={
  80 + 'verbose_name': 'Ticket',
  81 + 'verbose_name_plural': 'Ticket',
  82 + },
  83 + bases=(models.Model, hitcounter.models.HitCounterModelMixin),
  84 + ),
  85 + migrations.CreateModel(
  86 + name='Wiki',
  87 + fields=[
  88 + ('title', models.TextField(serialize=False, primary_key=True)),
  89 + ('wiki_text', models.TextField(blank=True)),
  90 + ('author', models.TextField(blank=True)),
  91 + ('collaborators', models.TextField(blank=True)),
  92 + ('created', models.DateTimeField(null=True, blank=True)),
  93 + ('modified', models.DateTimeField(null=True, blank=True)),
  94 + ('comment', models.TextField(blank=True)),
  95 + ('user', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)),
  96 + ],
  97 + options={
  98 + 'verbose_name': 'Wiki',
  99 + 'verbose_name_plural': 'Wiki',
  100 + },
  101 + bases=(models.Model, hitcounter.models.HitCounterModelMixin),
  102 + ),
141 103 ]
... ...
colab/proxy/trac/models.py
... ... @@ -7,23 +7,29 @@ from django.conf import settings
7 7  
8 8 from hitcounter.models import HitCounterModelMixin
9 9  
  10 +from colab.proxy.utils.models import Collaboration
10 11 from colab.accounts.models import User
  12 +from django.utils.translation import ugettext_lazy as _
11 13  
12 14  
13 15 class Attachment(models.Model, HitCounterModelMixin):
  16 + type = 'attachment'
  17 + icon_name = 'file'
14 18 url = models.TextField(primary_key=True)
15 19 attach_id = models.TextField()
16 20 used_by = models.TextField()
17 21 filename = models.TextField()
18 22 author = models.TextField(blank=True)
  23 + title = models.TextField(blank=True)
19 24 description = models.TextField(blank=True)
20 25 created = models.DateTimeField(blank=True)
21 26 mimetype = models.TextField(blank=True)
22 27 size = models.IntegerField(blank=True)
  28 + ipnr = models.TextField(blank=True)
23 29  
24 30 class Meta:
25   - managed = False
26   - db_table = 'attachment_view'
  31 + verbose_name = _('Attachment')
  32 + verbose_name_plural = _('Attachment')
27 33  
28 34 @property
29 35 def filepath(self):
... ... @@ -43,18 +49,23 @@ class Attachment(models.Model, HitCounterModelMixin):
43 49 except User.DoesNotExist:
44 50 return None
45 51  
46   -
47 52 class Revision(models.Model, HitCounterModelMixin):
48   - key = models.TextField(blank=True, primary_key=True)
  53 + update_field = 'created'
  54 + icon_name = 'align-right'
49 55 rev = models.TextField(blank=True)
50 56 author = models.TextField(blank=True)
51 57 message = models.TextField(blank=True)
  58 + description = models.TextField(blank=True)
52 59 repository_name = models.TextField(blank=True)
53 60 created = models.DateTimeField(blank=True, null=True)
54 61  
  62 + @property
  63 + def title(self):
  64 + return u'{} [{}]'.format(self.repository_name, self.rev)
  65 +
55 66 class Meta:
56   - managed = False
57   - db_table = 'revision_view'
  67 + verbose_name = _('Revision')
  68 + verbose_name_plural = _('Revision')
58 69  
59 70 def get_absolute_url(self):
60 71 return u'/changeset/{}/{}'.format(self.rev, self.repository_name)
... ... @@ -66,10 +77,11 @@ class Revision(models.Model, HitCounterModelMixin):
66 77 return None
67 78  
68 79  
69   -class Ticket(models.Model, HitCounterModelMixin):
70   - id = models.IntegerField(primary_key=True)
  80 +class Ticket(Collaboration, HitCounterModelMixin):
  81 + icon_name = 'tag'
  82 + type = 'ticket'
71 83 summary = models.TextField(blank=True)
72   - description = models.TextField(blank=True)
  84 + description_ticket = models.TextField(blank=True)
73 85 milestone = models.TextField(blank=True)
74 86 priority = models.TextField(blank=True)
75 87 component = models.TextField(blank=True)
... ... @@ -78,15 +90,28 @@ class Ticket(models.Model, HitCounterModelMixin):
78 90 reporter = models.TextField(blank=True)
79 91 author = models.TextField(blank=True)
80 92 status = models.TextField(blank=True)
  93 + tag = models.TextField(blank=True)
81 94 keywords = models.TextField(blank=True)
82 95 collaborators = models.TextField(blank=True)
83 96 created = models.DateTimeField(blank=True, null=True)
84 97 modified = models.DateTimeField(blank=True, null=True)
85   - modified_by = models.TextField(blank=True)
  98 + owner = models.TextField(blank=True)
  99 + resolution = models.TextField(blank=True)
  100 +
  101 + @property
  102 + def title(self):
  103 + return u'#{} - {}'.format(self.id, self.summary)
  104 +
  105 + @property
  106 + def description(self):
  107 + return u'{}\n{}\n{}\n{}\n{}\n{}\n{}'.format(
  108 + self.description_ticket, self.milestone, self.component,
  109 + self.severity, self.reporter, self.keywords, self.collaborators
  110 + )
86 111  
87 112 class Meta:
88   - managed = False
89   - db_table = 'ticket_view'
  113 + verbose_name = _('Ticket')
  114 + verbose_name_plural = _('Ticket')
90 115  
91 116 def get_absolute_url(self):
92 117 return u'/ticket/{}'.format(self.id)
... ... @@ -104,21 +129,26 @@ class Ticket(models.Model, HitCounterModelMixin):
104 129 return None
105 130  
106 131  
107   -class Wiki(models.Model, HitCounterModelMixin):
108   - name = models.TextField(primary_key=True)
  132 +class Wiki(Collaboration, HitCounterModelMixin):
  133 + type = "wiki"
  134 + icon_name = "book"
  135 + title = models.TextField(primary_key=True)
109 136 wiki_text = models.TextField(blank=True)
110 137 author = models.TextField(blank=True)
111 138 collaborators = models.TextField(blank=True)
112 139 created = models.DateTimeField(blank=True, null=True)
113 140 modified = models.DateTimeField(blank=True, null=True)
114   - modified_by = models.TextField(blank=True)
  141 +
  142 + @property
  143 + def description(self):
  144 + return u'{}\n{}'.format(self.wiki_text, self.collaborators)
115 145  
116 146 class Meta:
117   - managed = False
118   - db_table = 'wiki_view'
  147 + verbose_name = _('Wiki')
  148 + verbose_name_plural = _('Wiki')
119 149  
120 150 def get_absolute_url(self):
121   - return u'/wiki/{}'.format(self.name)
  151 + return u'/wiki/{}'.format(self.title)
122 152  
123 153 def get_author(self):
124 154 try:
... ... @@ -128,6 +158,6 @@ class Wiki(models.Model, HitCounterModelMixin):
128 158  
129 159 def get_modified_by(self):
130 160 try:
131   - return User.objects.get(username=self.modified_by)
  161 + return User.objects.get(username=self.author)
132 162 except User.DoesNotExist:
133 163 return None
... ...
colab/proxy/trac/search_indexes.py
... ... @@ -75,7 +75,7 @@ class AttachmentIndex(BaseIndex, indexes.Indexable):
75 75  
76 76  
77 77 class WikiIndex(BaseIndex, indexes.Indexable):
78   - title = indexes.CharField(model_attr='name')
  78 + title = indexes.CharField(model_attr='title')
79 79 collaborators = indexes.CharField(
80 80 model_attr='collaborators',
81 81 null=True,
... ...
colab/proxy/trac/templates/search/indexes/trac/attachment_text.txt
... ... @@ -0,0 +1,15 @@
  1 +{{ object.filename }}
  2 +{{ object.filename|slugify }}
  3 +{{ object.description }}
  4 +{{ object.description|slugify }}
  5 +{{ object.used_by }}
  6 +{{ object.mimetype }}
  7 +{{ object.get_author.get_full_name }}
  8 +
  9 +{% for k, v in extracted.metadata.items %}
  10 + {% for val in v %}
  11 + {{ k }}: {{ val|safe }}
  12 + {% endfor %}
  13 +{% endfor %}
  14 +
  15 +{{ extracted.contents|striptags|safe }}
... ...
colab/proxy/trac/templates/search/indexes/trac/revision_text.txt
... ... @@ -0,0 +1,8 @@
  1 +{{ object.repository_name }}
  2 +{{ object.repository_name|slugify }}
  3 +{{ object.rev }}
  4 +{{ object.rev|slugify }}
  5 +{% firstof object.get_author.get_full_name object.author %}
  6 +{% firstof object.get_author.get_full_name|slugify object.author|slugify %}
  7 +{{ object.message }}
  8 +{{ object.message|slugify }}
... ...
colab/proxy/trac/templates/search/indexes/trac/ticket_text.txt
... ... @@ -0,0 +1,20 @@
  1 +{{ object.summary }}
  2 +{{ object.summary|slugify }}
  3 +{{ object.description }}
  4 +{{ object.description|slugify }}
  5 +{{ object.milestone }}
  6 +{{ object.milestone|slugify }}
  7 +{{ object.component|slugify }}
  8 +{{ object.version }}
  9 +{{ object.severity }}
  10 +{{ object.severity|slugify }}
  11 +{{ object.reporter }}
  12 +{{ object.reporter|slugify }}
  13 +{% firstof object.get_author.get_fullname or object.author %}
  14 +{% firstof object.get_author.get_fullname|slugify or object.author|slugify %}
  15 +{{ object.status }}
  16 +{{ object.status|slugify }}
  17 +{{ object.keywords }}
  18 +{{ object.keywords|slugify }}
  19 +{{ object.collaborators }}
  20 +{{ object.collaborators|slugify }}
... ...
colab/proxy/trac/templates/search/indexes/trac/wiki_text.txt
... ... @@ -0,0 +1,9 @@
  1 +{{ object.author }}
  2 +{{ object.get_author.get_full_name }}
  3 +{{ object.get_author.get_full_name|slugify }}
  4 +{{ object.name }}
  5 +{{ object.name|slugify }}
  6 +{{ object.collaborators }}
  7 +{{ object.collaborators|slugify }}
  8 +{{ object.wiki_text }}
  9 +{{ object.wiki_text|slugify }}
... ...
colab/proxy/trac/tests/__init__.py
colab/proxy/trac/tests/test_data_api.py
... ... @@ -0,0 +1,32 @@
  1 +"""
  2 +Test DataAPI class.
  3 +Objective: Test parameters and behavior.
  4 +"""
  5 +from colab.proxy.trac.data_api import TracDataAPI
  6 +
  7 +from django.db import connections
  8 +from django.test import TestCase
  9 +
  10 +
  11 +class TracDataAPITest(TestCase):
  12 +
  13 + fixtures = ["trac_data.json"]
  14 +
  15 + def setUp(self):
  16 + self.connection = connections['default']
  17 + self.cursor = self.connection.cursor()
  18 +
  19 + def tearDown(self):
  20 + self.connection.close()
  21 +
  22 + def test_dict_fetch_all(self):
  23 + trac_dict = TracDataAPI()
  24 + self.cursor.execute(''' SELECT * FROM trac_wiki;''')
  25 + dict_result = trac_dict.dictfetchall(self.cursor)
  26 + self.assertIn('collaborators', dict_result[0])
  27 +
  28 + def test_dict_fetch_all_is_dict(self):
  29 + trac_dict = TracDataAPI()
  30 + self.cursor.execute(''' SELECT * FROM trac_wiki;''')
  31 + dict_result = trac_dict.dictfetchall(self.cursor)
  32 + self.assertIsInstance(dict_result[0], dict)
... ...
colab/proxy/trac/tests/test_trac.py
... ... @@ -0,0 +1,205 @@
  1 +"""
  2 +Test Trac class.
  3 +Objective: Test parameters and behavior.
  4 +"""
  5 +from colab.accounts.models import User
  6 +from colab.proxy.trac.models import Attachment, Revision, Ticket, Wiki
  7 +from django.test import TestCase
  8 +
  9 +
  10 +class AttachmentTest(TestCase):
  11 +
  12 + def setUp(self):
  13 + self.attachment = self.create_attachment()
  14 +
  15 + def tearDown(self):
  16 + pass
  17 +
  18 + def create_attachment(self):
  19 + attachment = Attachment()
  20 + attachment.type = 'attachment'
  21 + attachment.icon_name = 'file'
  22 + attachment.url = 'example.com'
  23 + attachment.attach_id = 'attach_id'
  24 + attachment.used_by = 'used_by'
  25 + attachment.filename = 'filename'
  26 + attachment.author = 'author'
  27 + attachment.title = 'title'
  28 + attachment.description = 'description'
  29 + attachment.modified = '1994-11-05T08:15:30-05:00'
  30 + attachment.created = '1994-11-05T08:15:30-05:00'
  31 + attachment.mimetype = 'mimetype'
  32 + attachment.size = 20
  33 + attachment.save()
  34 +
  35 + return attachment
  36 +
  37 + def test_validade_filepath(self):
  38 + file_path = '/mnt/trac/attachments/used_by/attach_id/filename'
  39 + self.assertEqual(file_path, self.attachment.filepath)
  40 +
  41 + def test_validade_absolute_url(self):
  42 + absolute_url = u'/raw-attachment/example.com'
  43 + self.assertEqual(absolute_url, self.attachment.get_absolute_url())
  44 +
  45 + def test_validade_author(self):
  46 + author = 'author'
  47 + self.user = create_user()
  48 + self.assertEqual(author, str(self.attachment.get_author()))
  49 +
  50 + def test_invalidade_author(self):
  51 + self.assertEqual(None, self.attachment.get_author())
  52 +
  53 +
  54 +class RevisionTest(TestCase):
  55 + def setUp(self):
  56 + self.revision = self.create_revision()
  57 +
  58 + def create_revision(self):
  59 + revision = Revision()
  60 + revision.update_field = 'created'
  61 + revision.icon_name = 'align-right'
  62 + revision.rev = 'rev'
  63 + revision.author = 'author'
  64 + revision.message = 'message'
  65 + revision.description = 'description'
  66 + revision.repository_name = 'repository'
  67 + revision.created = '1994-11-05T08:15:30-05:00'
  68 + revision.modified = '1994-11-05T08:15:30-05:00'
  69 + revision.save()
  70 +
  71 + return revision
  72 +
  73 + def test_title(self):
  74 + title = 'repository [rev]'
  75 + self.assertEqual(title, self.revision.title)
  76 +
  77 + def test_get_absolute_url(self):
  78 + absolute_url = '/changeset/rev/repository'
  79 + self.assertEqual(absolute_url, self.revision.get_absolute_url())
  80 +
  81 + def test_get_author(self):
  82 + author = 'author'
  83 + self.user = create_user()
  84 + self.assertEqual(author, str(self.revision.get_author()))
  85 +
  86 + def test_invalid_get_author(self):
  87 + self.assertEqual(None, self.revision.get_author())
  88 +
  89 +
  90 +class TicketTest(TestCase):
  91 + def setUp(self):
  92 + self.ticket = self.create_ticket()
  93 +
  94 + def create_ticket(self):
  95 + ticket = Ticket()
  96 + ticket.icon_name = 'tag'
  97 + ticket.type = 'ticket'
  98 + ticket.id = 20
  99 + ticket.summary = 'summary'
  100 + ticket.description_ticket = 'description'
  101 + ticket.milestone = 'milestone'
  102 + ticket.priority = 'priority'
  103 + ticket.component = 'component'
  104 + ticket.version = 'version'
  105 + ticket.severity = 'severity'
  106 + ticket.reporter = 'reporter'
  107 + ticket.author = 'author'
  108 + ticket.status = 'status'
  109 + ticket.tag = 'tag'
  110 + ticket.keywords = 'keywords'
  111 + ticket.collaborators = 'collaborators'
  112 + ticket.created = '1994-11-05T08:15:30-05:00'
  113 + ticket.modified = '1994-11-05T08:15:30-05:00'
  114 + ticket.save()
  115 +
  116 + return ticket
  117 +
  118 + def test_title(self):
  119 + title = '#20 - summary'
  120 + self.assertEqual(title, self.ticket.title)
  121 +
  122 + def test_description(self):
  123 + description1 = u'description\nmilestone\ncomponent\nseverity'
  124 + description2 = '\nreporter\nkeywords\ncollaborators'
  125 + description_test = description1 + description2
  126 + self.assertEqual(description_test, self.ticket.description)
  127 +
  128 + def test_get_absolute_url(self):
  129 + absolute_url = '/ticket/20'
  130 + self.assertEqual(absolute_url, self.ticket.get_absolute_url())
  131 +
  132 + def test_get_author(self):
  133 + author = 'author'
  134 + self.user = create_user()
  135 + self.assertEqual(author, str(self.ticket.get_author()))
  136 +
  137 + def test_invalid_get_author(self):
  138 + author = None
  139 + self.assertEqual(author, self.ticket.get_author())
  140 +
  141 + def test_get_modified_by(self):
  142 + self.user = create_user()
  143 + get_modified_by = str(self.ticket.get_modified_by())
  144 + self.assertEqual(str(self.ticket.modified_by), get_modified_by)
  145 +
  146 + def test_invalid_get_modified_by(self):
  147 + get_modified_by = self.ticket.get_modified_by()
  148 + self.assertEqual(None, get_modified_by)
  149 +
  150 +
  151 +class WikiTest(TestCase):
  152 + def setUp(self):
  153 + self.wiki = self.create_wiki()
  154 +
  155 + def create_wiki(self):
  156 + wiki = Wiki()
  157 + wiki.type = "wiki"
  158 + wiki.icon_name = "book"
  159 + wiki.title = 'title'
  160 + wiki.wiki_text = 'wiki_text'
  161 + wiki.author = 'author'
  162 + wiki.collaborators = 'collaborators'
  163 + wiki.created = '1994-11-05T08:15:30-05:00'
  164 + wiki.modified = '1994-11-05T08:15:30-05:00'
  165 + wiki.save()
  166 +
  167 + return wiki
  168 +
  169 + def test_description(self):
  170 + description_test = u'wiki_text\ncollaborators'
  171 + self.assertEqual(description_test, self.wiki.description)
  172 +
  173 + def test_get_absolute_url(self):
  174 + absolute_url = u'/wiki/title'
  175 + self.assertEqual(absolute_url, self.wiki.get_absolute_url())
  176 +
  177 + def test_get_author(self):
  178 + author = 'author'
  179 + self.user = create_user()
  180 + self.assertEqual(author, str(self.wiki.get_author()))
  181 +
  182 + def test_invalid_get_author(self):
  183 + author = None
  184 + self.assertEqual(author, self.wiki.get_author())
  185 +
  186 + def test_get_modified_by(self):
  187 + self.user = create_user()
  188 + get_modified_by = str(self.wiki.get_modified_by())
  189 + modified_by = "author"
  190 + self.assertEqual(modified_by, get_modified_by)
  191 +
  192 + def test_invalid_get_modified_by(self):
  193 + get_modified_by = self.wiki.get_modified_by()
  194 + self.assertEqual(None, get_modified_by)
  195 +
  196 +
  197 +def create_user():
  198 + user = User()
  199 + user.username = "author"
  200 + user.first_name = "FisrtName"
  201 + user.last_name = "LastName"
  202 + user.modified_by = "author"
  203 + user.save()
  204 +
  205 + return user
... ...
docs/source/conf.py
... ... @@ -18,7 +18,9 @@ import os
18 18 # If extensions (or modules to document with autodoc) are in another directory,
19 19 # add these directories to sys.path here. If the directory is relative to the
20 20 # documentation root, use os.path.abspath to make it absolute, like shown here.
21   -#sys.path.insert(0, os.path.abspath('.'))
  21 +sys.path.insert(0, os.path.abspath('../../colab/proxy'))
  22 +from django.conf import settings
  23 +settings.configure()
22 24  
23 25 # -- General configuration ------------------------------------------------
24 26  
... ...
docs/source/dev.rst
1 1 Developer Documentation
2   -==================
  2 +=======================
3 3  
4 4 Getting Started
5 5 ---------------
... ...
docs/source/index.rst
... ... @@ -30,6 +30,8 @@ Contents:
30 30 user
31 31 plugindev
32 32 dev
  33 + trac
  34 +
33 35  
34 36  
35 37 Indices and tables
... ... @@ -38,4 +40,3 @@ Indices and tables
38 40 * :ref:`genindex`
39 41 * :ref:`modindex`
40 42 * :ref:`search`
41   -
... ...
docs/source/plugindev.rst
1 1 Plugin Developer Documentation
2   -==================
  2 +==============================
3 3  
4 4 Getting Started
5 5 ---------------
... ...
docs/source/trac.rst
... ... @@ -0,0 +1,13 @@
  1 +trac package
  2 +============
  3 +
  4 +Submodules
  5 +----------
  6 +
  7 +trac.data_api module
  8 +--------------------
  9 +
  10 +.. automodule:: trac.data_api
  11 + :members:
  12 + :undoc-members:
  13 + :show-inheritance:
... ...
docs/source/user.rst
... ... @@ -16,6 +16,72 @@ Plugins
16 16 -------
17 17 .. TODO
18 18  
  19 +Trac
  20 +++++
  21 +
  22 +
  23 +Since Trac already installed:
  24 +
  25 +- Easily, you can install it as follows:
  26 +
  27 +.. code-block:: sh
  28 +
  29 + $ pip install trac
  30 +
  31 +To enable Trac plugin must first configure the trac database in /etc/colab/settings.yml:
  32 +
  33 +1. vim /etc/colab/settings.yaml
  34 +
  35 +.. code-block:: yaml
  36 +
  37 + DATABASES:
  38 + default:
  39 + ENGINE: django.db.backends.postgresql_psycopg2
  40 + HOST: localhost
  41 + NAME: colab
  42 + USER: colab
  43 + PASSWORD: colab
  44 + trac:
  45 + ENGINE: django.db.backends.postgresql_psycopg2
  46 + HOST: localhost
  47 + NAME: trac
  48 + USER: colab
  49 + PASSWORD: colab
  50 +
  51 +- Yet this file uncomment in PROXIED_APPS the Trac:
  52 +
  53 +.. code-block:: yaml
  54 +
  55 + PROXIED_APPS:
  56 + # gitlab:
  57 + # upstream: 'http://localhost:8090/gitlab/'
  58 + # private_token: ''
  59 + trac:
  60 + upstream: 'http://localhost:5000/trac/'
  61 +
  62 +- Create the database in postgresql with user
  63 +
  64 +.. code-block:: sh
  65 +
  66 + $ sudo -u postgres psql
  67 + $ create database trac owner colab;
  68 +
  69 +- Now, generate the migrations:
  70 +
  71 +.. code-block:: sh
  72 +
  73 + # Since you are in the folder colab
  74 + $ workon colab
  75 + $ colab-admin makemigrations
  76 + $ colab-admin migrate trac
  77 +
  78 +- Finally, just import the Trac data (may take a few minutes):
  79 +
  80 +.. code-block:: sh
  81 +
  82 + # Since you are in the folder colab
  83 + $ colab-admin import_proxy_data
  84 +
19 85 Settings
20 86 --------
21 87  
... ...
setup.py
... ... @@ -3,7 +3,7 @@ from setuptools import setup, find_packages
3 3  
4 4  
5 5 REQUIREMENTS = [
6   - 'Django==1.7.5',
  6 + 'Django==1.7.7',
7 7 'psycopg2==2.5.1',
8 8 'django-piston==0.2.3',
9 9 'pytz==2011n',
... ...
tests/run.py
... ... @@ -6,7 +6,6 @@ import sys
6 6 os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings'
7 7 os.environ['COLAB_SETTINGS'] = 'tests/settings.yaml'
8 8 os.environ['COVERAGE_PROCESS_START'] = '.coveragerc'
9   -os.environ['REUSE_DB'] = '0'
10 9  
11 10 import django
12 11 import coverage
... ... @@ -14,7 +13,6 @@ import coverage
14 13 from django.test.utils import get_runner
15 14 from django.conf import settings
16 15  
17   -
18 16 def runtests():
19 17 if django.VERSION >= (1, 7, 0):
20 18 django.setup()
... ...
tests/settings.yaml
... ... @@ -64,10 +64,10 @@ ROBOTS_NOINDEX: false
64 64  
65 65 ### Colab proxied apps
66 66 PROXIED_APPS:
67   - gitlab:
68   - upstream: 'http://localhost:8090/gitlab/'
69   - private_token: ''
70   -# trac:
71   -# upstream: 'http://localhost:5000/trac/'
  67 +# gitlab:
  68 +# upstream: 'http://localhost:8090/gitlab/'
  69 +# private_token: ''
  70 + trac:
  71 + upstream: 'http://localhost:5000/trac/'
72 72  
73 73  
... ...
vagrant/centos.sh
... ... @@ -19,7 +19,7 @@ fi
19 19  
20 20 yum -y groupinstall "Development tools"
21 21  
22   -yum install -y git unzip mercurial libev-devel gettext libxml2-devel libxslt-devel openssl-devel libffi-devel libjpeg-turbo-devel zlib-devel freetype-devel postgresql-devel python-devel postgresql-server
  22 +yum install -y git unzip mercurial libev-devel gettext libxml2-devel libxslt-devel openssl-devel libffi-devel libjpeg-turbo-devel zlib-devel freetype-devel postgresql-devel python-devel postgresql-server java
23 23  
24 24 ### Install Virtualenvwrapper
25 25 which pip2.7 > /dev/null ||
... ...
vagrant/misc/etc/init.d/solr
... ... @@ -0,0 +1,45 @@
  1 +#!/bin/bash
  2 +# chkconfig: 2345 95 20
  3 +# description: Solr
  4 +# processname: myscript
  5 +#
  6 +#-----------------------------------------------------
  7 +# Script for running solr as a service.
  8 +#
  9 +# Usage: service solr {start|stop|restart|status}"
  10 +#
  11 +#-----------------------------------------------------
  12 +# This should be placed in /etc/init.d
  13 +
  14 +. /etc/rc.d/init.d/functions
  15 +
  16 +# Path to pid file
  17 +PIDFILE=/var/run/solr.pid
  18 +
  19 +# Service name
  20 +NAME="Solr"
  21 +
  22 +# Service description
  23 +DESC="start/stop Solr Server"
  24 +
  25 +SOLR_INIT="/home/vagrant/solr-4.10.3/start.sh"
  26 +
  27 +case $1 in
  28 + start)
  29 + action "Starting ${NAME}: " daemon --pidfile $PIDFILE $SOLR_INIT
  30 + ;;
  31 + stop)
  32 + action "Stopping ${NAME}: " killproc -p $PIDFILE
  33 + ;;
  34 + restart)
  35 + $0 stop
  36 + $0 start
  37 + ;;
  38 + status)
  39 + status -p $PIDFILE solr
  40 + ;;
  41 + *)
  42 + echo "Usage: $0 {start|stop|restart|status}"
  43 + exit 3
  44 + ;;
  45 +esac
... ...
vagrant/provision.sh
... ... @@ -2,6 +2,7 @@
2 2  
3 3 set -x
4 4  
  5 +### Configure Colab
5 6 export VIRTUALENVWRAPPER_PYTHON="/usr/bin/python2.7"
6 7  
7 8 set +e
... ... @@ -32,3 +33,22 @@ fi
32 33  
33 34 colab-admin migrate
34 35 colab-admin loaddata /vagrant/tests/test_data.json
  36 +
  37 +
  38 +### Install solr
  39 +
  40 +colab-admin build_solr_schema -f /tmp/schema.xml
  41 +
  42 +export SOLR_VERSION=4.10.3
  43 +export SOLR_CONFS="/tmp/schema.xml"
  44 +
  45 +$basedir/ci/install_solr.sh
  46 +/home/vagrant/solr-4.10.3/bin/solr stop -p 8983
  47 +
  48 +# Init.d Solr files
  49 +sudo cp $basedir/vagrant/misc/etc/init.d/solr /etc/init.d/
  50 +cp $basedir/vagrant/solr/start.sh /home/vagrant/solr-$SOLR_VERSION
  51 +sudo chkconfig --add solr
  52 +sudo service solr start
  53 +
  54 +colab-admin rebuild_index --noinput
... ...
vagrant/solr/start.sh
... ... @@ -0,0 +1,20 @@
  1 +#!/bin/bash
  2 +
  3 +# Directory where solr is installed
  4 +SOLR_HOME=/home/vagrant/solr-4.10.3/example
  5 +
  6 +# Java options for Solr
  7 +OPTIONS="-Xmx128m"
  8 +
  9 +# Path to pid file
  10 +PIDFILE=/var/run/solr.pid
  11 +
  12 +# Path to log file
  13 +LOG_FILE=/var/log/solr.log
  14 +
  15 +COMMAND="java $OPTIONS -jar start.jar"
  16 +
  17 +cd $SOLR_HOME
  18 +nohup $COMMAND > $LOG_FILE 2>&1 &
  19 +echo $! > $PIDFILE
  20 +exit $?
... ...
vagrant/ubuntu.sh
... ... @@ -5,7 +5,7 @@ set -ex
5 5 ### Install dependencies
6 6 apt-get update
7 7  
8   -apt-get install curl git unzip mercurial build-essential libev-dev gettext libxml2-dev libxslt1-dev libssl-dev libffi-dev libjpeg-dev zlib1g-dev libfreetype6-dev libpq-dev python-dev postgresql virtualenvwrapper python-pip -y
  8 +apt-get install curl git unzip mercurial build-essential libev-dev gettext libxml2-dev libxslt1-dev libssl-dev libffi-dev libjpeg-dev zlib1g-dev libfreetype6-dev libpq-dev python-dev postgresql virtualenvwrapper python-pip java-common -y
9 9  
10 10  
11 11 ### Create conf directory
... ...