Commit 5fe84f6f5ddff12b0d7e52d40adee82e822b94bc
1 parent
8b5c4784
Exists in
master
and in
1 other branch
Add gitlab code at colab_gitlab
Signed-off-by: Gustavo Jaruga <darksshades@gmail.com> Signed-off-by: Alexandre Barbosa <alexandreab@live.com>
Showing
15 changed files
with
853 additions
and
0 deletions
Show diff stats
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | + | ||
2 | +from django.utils.translation import ugettext_lazy as _ | ||
3 | + | ||
4 | +from colab.plugins.utils.apps import ColabProxiedAppConfig | ||
5 | + | ||
6 | + | ||
7 | +class ProxyGitlabAppConfig(ColabProxiedAppConfig): | ||
8 | + name = 'colab_gitlab' | ||
9 | + verbose_name = 'Gitlab Proxy' | ||
10 | + | ||
11 | + menu = { | ||
12 | + 'title': _('Code'), | ||
13 | + 'links': ( | ||
14 | + (_('Public Projects'), 'public/projects'), | ||
15 | + ), | ||
16 | + 'auth_links': ( | ||
17 | + (_('Profile'), 'profile'), | ||
18 | + (_('New Project'), 'projects/new'), | ||
19 | + (_('Projects'), 'dashboard/projects'), | ||
20 | + (_('Groups'), 'profile/groups'), | ||
21 | + (_('Issues'), 'dashboard/issues'), | ||
22 | + (_('Merge Requests'), 'dashboard/merge_requests'), | ||
23 | + | ||
24 | + ), | ||
25 | + } |
@@ -0,0 +1,205 @@ | @@ -0,0 +1,205 @@ | ||
1 | +import json | ||
2 | +import urllib | ||
3 | +import urllib2 | ||
4 | +import logging | ||
5 | + | ||
6 | +from dateutil.parser import parse | ||
7 | + | ||
8 | +from django.conf import settings | ||
9 | +from django.db.models.fields import DateTimeField | ||
10 | + | ||
11 | +from colab_gitlab.models import (GitlabProject, GitlabMergeRequest, | ||
12 | + GitlabComment, GitlabIssue) | ||
13 | +from colab.plugins.utils.proxy_data_api import ProxyDataAPI | ||
14 | + | ||
15 | +LOGGER = logging.getLogger('colab.plugin.gitlab') | ||
16 | + | ||
17 | + | ||
18 | +class GitlabDataAPI(ProxyDataAPI): | ||
19 | + | ||
20 | + def get_request_url(self, path, **kwargs): | ||
21 | + proxy_config = settings.PROXIED_APPS.get(self.app_label, {}) | ||
22 | + | ||
23 | + upstream = proxy_config.get('upstream') | ||
24 | + kwargs['private_token'] = proxy_config.get('private_token') | ||
25 | + params = urllib.urlencode(kwargs) | ||
26 | + | ||
27 | + if upstream[-1] == '/': | ||
28 | + upstream = upstream[:-1] | ||
29 | + | ||
30 | + return u'{}{}?{}'.format(upstream, path, params) | ||
31 | + | ||
32 | + def get_json_data(self, api_url, page, pages=1000): | ||
33 | + url = self.get_request_url(api_url, per_page=pages, | ||
34 | + page=page) | ||
35 | + | ||
36 | + try: | ||
37 | + data = urllib2.urlopen(url, timeout=10) | ||
38 | + json_data = json.load(data) | ||
39 | + except urllib2.URLError: | ||
40 | + LOGGER.exception("Connection timeout: " + url) | ||
41 | + json_data = [] | ||
42 | + | ||
43 | + return json_data | ||
44 | + | ||
45 | + def fill_object_data(self, element, _object): | ||
46 | + for field in _object._meta.fields: | ||
47 | + try: | ||
48 | + if field.name == "user": | ||
49 | + _object.update_user( | ||
50 | + element["author"]["username"]) | ||
51 | + continue | ||
52 | + if field.name == "project": | ||
53 | + _object.project_id = element["project_id"] | ||
54 | + continue | ||
55 | + | ||
56 | + if isinstance(field, DateTimeField): | ||
57 | + value = parse(element[field.name]) | ||
58 | + else: | ||
59 | + value = element[field.name] | ||
60 | + | ||
61 | + setattr(_object, field.name, value) | ||
62 | + except KeyError: | ||
63 | + continue | ||
64 | + | ||
65 | + return _object | ||
66 | + | ||
67 | + def fetch_projects(self): | ||
68 | + page = 1 | ||
69 | + projects = [] | ||
70 | + | ||
71 | + while True: | ||
72 | + json_data = self.get_json_data('/api/v3/projects/all', page) | ||
73 | + page = page + 1 | ||
74 | + | ||
75 | + if not len(json_data): | ||
76 | + break | ||
77 | + | ||
78 | + for element in json_data: | ||
79 | + project = GitlabProject() | ||
80 | + self.fill_object_data(element, project) | ||
81 | + projects.append(project) | ||
82 | + | ||
83 | + return projects | ||
84 | + | ||
85 | + def fetch_merge_request(self, projects): | ||
86 | + all_merge_request = [] | ||
87 | + | ||
88 | + for project in projects: | ||
89 | + page = 1 | ||
90 | + while True: | ||
91 | + url = '/api/v3/projects/{}/merge_requests'.format(project.id) | ||
92 | + json_data_mr = self.get_json_data(url, page) | ||
93 | + page = page + 1 | ||
94 | + | ||
95 | + if len(json_data_mr) == 0: | ||
96 | + break | ||
97 | + | ||
98 | + for element in json_data_mr: | ||
99 | + single_merge_request = GitlabMergeRequest() | ||
100 | + self.fill_object_data(element, single_merge_request) | ||
101 | + all_merge_request.append(single_merge_request) | ||
102 | + | ||
103 | + return all_merge_request | ||
104 | + | ||
105 | + def fetch_issue(self, projects): | ||
106 | + all_issues = [] | ||
107 | + | ||
108 | + for project in projects: | ||
109 | + page = 1 | ||
110 | + while True: | ||
111 | + url = '/api/v3/projects/{}/issues'.format(project.id) | ||
112 | + json_data_issue = self.get_json_data(url, page) | ||
113 | + page = page + 1 | ||
114 | + | ||
115 | + if len(json_data_issue) == 0: | ||
116 | + break | ||
117 | + | ||
118 | + for element in json_data_issue: | ||
119 | + single_issue = GitlabIssue() | ||
120 | + self.fill_object_data(element, single_issue) | ||
121 | + all_issues.append(single_issue) | ||
122 | + | ||
123 | + return all_issues | ||
124 | + | ||
125 | + def fetch_comments(self): | ||
126 | + all_comments = [] | ||
127 | + all_comments.extend(self.fetch_comments_MR()) | ||
128 | + all_comments.extend(self.fetch_comments_issues()) | ||
129 | + | ||
130 | + return all_comments | ||
131 | + | ||
132 | + def fetch_comments_MR(self): | ||
133 | + all_comments = [] | ||
134 | + all_merge_requests = GitlabMergeRequest.objects.all() | ||
135 | + | ||
136 | + for merge_request in all_merge_requests: | ||
137 | + page = 1 | ||
138 | + while True: | ||
139 | + url = '/api/v3/projects/{}/merge_requests/{}/notes'.format( | ||
140 | + merge_request.project_id, merge_request.id) | ||
141 | + json_data_mr = self.get_json_data(url, page) | ||
142 | + page = page + 1 | ||
143 | + | ||
144 | + if len(json_data_mr) == 0: | ||
145 | + break | ||
146 | + | ||
147 | + for element in json_data_mr: | ||
148 | + single_comment = GitlabComment() | ||
149 | + self.fill_object_data(element, single_comment) | ||
150 | + single_comment.project = merge_request.project | ||
151 | + single_comment.issue_comment = False | ||
152 | + single_comment.parent_id = merge_request.id | ||
153 | + all_comments.append(single_comment) | ||
154 | + | ||
155 | + return all_comments | ||
156 | + | ||
157 | + def fetch_comments_issues(self): | ||
158 | + all_comments = [] | ||
159 | + all_issues = GitlabIssue.objects.all() | ||
160 | + | ||
161 | + for issue in all_issues: | ||
162 | + page = 1 | ||
163 | + while True: | ||
164 | + url = '/api/v3/projects/{}/issues/{}/notes'.format( | ||
165 | + issue.project_id, issue.id) | ||
166 | + json_data_mr = self.get_json_data(url, page) | ||
167 | + page = page + 1 | ||
168 | + | ||
169 | + if len(json_data_mr) == 0: | ||
170 | + break | ||
171 | + | ||
172 | + for element in json_data_mr: | ||
173 | + single_comment = GitlabComment() | ||
174 | + self.fill_object_data(element, single_comment) | ||
175 | + single_comment.project = issue.project | ||
176 | + single_comment.issue_comment = True | ||
177 | + single_comment.parent_id = issue.id | ||
178 | + all_comments.append(single_comment) | ||
179 | + | ||
180 | + return all_comments | ||
181 | + | ||
182 | + def fetch_data(self): | ||
183 | + LOGGER.info("Importing Projects") | ||
184 | + projects = self.fetch_projects() | ||
185 | + for datum in projects: | ||
186 | + datum.save() | ||
187 | + | ||
188 | + LOGGER.info("Importing Merge Requests") | ||
189 | + merge_request_list = self.fetch_merge_request(projects) | ||
190 | + for datum in merge_request_list: | ||
191 | + datum.save() | ||
192 | + | ||
193 | + LOGGER.info("Importing Issues") | ||
194 | + issue_list = self.fetch_issue(projects) | ||
195 | + for datum in issue_list: | ||
196 | + datum.save() | ||
197 | + | ||
198 | + LOGGER.info("Importing Comments") | ||
199 | + comments_list = self.fetch_comments() | ||
200 | + for datum in comments_list: | ||
201 | + datum.save() | ||
202 | + | ||
203 | + @property | ||
204 | + def app_label(self): | ||
205 | + return 'gitlab' |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +<rules | ||
2 | + xmlns="http://namespaces.plone.org/diazo" | ||
3 | + xmlns:css="http://namespaces.plone.org/diazo/css" | ||
4 | + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | ||
5 | + | ||
6 | + <before theme-children="/html/head" content-children="/html/head" /> | ||
7 | + <before css:theme-children="#main-content" css:content-children="body" /> | ||
8 | + | ||
9 | + <merge attributes="class" css:theme="body" css:content="body" /> | ||
10 | + | ||
11 | + <!-- Add gitlab properties --> | ||
12 | + <merge attributes="data-page" css:theme="body" css:content="body" /> | ||
13 | + <merge attributes="data-project-id" css:theme="body" css:content="body" /> | ||
14 | + | ||
15 | + <drop css:content="#top-panel" /> | ||
16 | + <drop css:content=".navbar-gitlab" /> | ||
17 | + <drop css:content=".git-clone-holder .btn:contains('HTTPS')" /> | ||
18 | +</rules> |
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | +from __future__ import unicode_literals | ||
3 | + | ||
4 | +from django.db import models, migrations | ||
5 | + | ||
6 | + | ||
7 | +class Migration(migrations.Migration): | ||
8 | + | ||
9 | + dependencies = [ | ||
10 | + ] | ||
11 | + | ||
12 | + operations = [ | ||
13 | + migrations.CreateModel( | ||
14 | + name='GitlabProject', | ||
15 | + fields=[ | ||
16 | + ('id', models.IntegerField(serialize=False, primary_key=True)), | ||
17 | + ('description', models.TextField()), | ||
18 | + ('public', models.BooleanField(default=True)), | ||
19 | + ('name', models.TextField()), | ||
20 | + ('name_with_namespace', models.TextField()), | ||
21 | + ('created_at', models.DateTimeField(blank=True)), | ||
22 | + ('last_activity_at', models.DateTimeField(blank=True)), | ||
23 | + ], | ||
24 | + options={ | ||
25 | + }, | ||
26 | + bases=(models.Model,), | ||
27 | + ), | ||
28 | + ] |
@@ -0,0 +1,69 @@ | @@ -0,0 +1,69 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | +from __future__ import unicode_literals | ||
3 | + | ||
4 | +from django.db import models, migrations | ||
5 | +import django.db.models.deletion | ||
6 | +from django.conf import settings | ||
7 | + | ||
8 | + | ||
9 | +class Migration(migrations.Migration): | ||
10 | + | ||
11 | + dependencies = [ | ||
12 | + migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
13 | + ('colab_gitlab', '0001_initial'), | ||
14 | + ] | ||
15 | + | ||
16 | + operations = [ | ||
17 | + migrations.CreateModel( | ||
18 | + name='GitlabComment', | ||
19 | + fields=[ | ||
20 | + ('id', models.IntegerField(serialize=False, primary_key=True)), | ||
21 | + ('body', models.TextField()), | ||
22 | + ('created_at', models.DateTimeField(blank=True)), | ||
23 | + ('user', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)), | ||
24 | + ], | ||
25 | + options={ | ||
26 | + 'verbose_name': 'Gitlab Comments', | ||
27 | + 'verbose_name_plural': 'Gitlab Comments', | ||
28 | + }, | ||
29 | + bases=(models.Model,), | ||
30 | + ), | ||
31 | + migrations.CreateModel( | ||
32 | + name='GitlabIssue', | ||
33 | + fields=[ | ||
34 | + ('id', models.IntegerField(serialize=False, primary_key=True)), | ||
35 | + ('title', models.TextField()), | ||
36 | + ('description', models.TextField()), | ||
37 | + ('state', models.TextField()), | ||
38 | + ('project', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='colab_gitlab.GitlabProject', null=True)), | ||
39 | + ('user', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)), | ||
40 | + ], | ||
41 | + options={ | ||
42 | + 'verbose_name': 'Gitlab Collaboration', | ||
43 | + 'verbose_name_plural': 'Gitlab Collaborations', | ||
44 | + }, | ||
45 | + bases=(models.Model,), | ||
46 | + ), | ||
47 | + migrations.CreateModel( | ||
48 | + name='GitlabMergeRequest', | ||
49 | + fields=[ | ||
50 | + ('id', models.IntegerField(serialize=False, primary_key=True)), | ||
51 | + ('target_branch', models.TextField()), | ||
52 | + ('source_branch', models.TextField()), | ||
53 | + ('description', models.TextField()), | ||
54 | + ('title', models.TextField()), | ||
55 | + ('state', models.TextField()), | ||
56 | + ('project', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='colab_gitlab.GitlabProject', null=True)), | ||
57 | + ('user', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, null=True)), | ||
58 | + ], | ||
59 | + options={ | ||
60 | + 'verbose_name': 'Gitlab Merge Request', | ||
61 | + 'verbose_name_plural': 'Gitlab Merge Requests', | ||
62 | + }, | ||
63 | + bases=(models.Model,), | ||
64 | + ), | ||
65 | + migrations.AlterModelOptions( | ||
66 | + name='gitlabproject', | ||
67 | + options={'verbose_name': 'Gitlab Project', 'verbose_name_plural': 'Gitlab Projects'}, | ||
68 | + ), | ||
69 | + ] |
@@ -0,0 +1,61 @@ | @@ -0,0 +1,61 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | +from __future__ import unicode_literals | ||
3 | + | ||
4 | +from django.db import models, migrations | ||
5 | +import django.db.models.deletion | ||
6 | + | ||
7 | + | ||
8 | +class Migration(migrations.Migration): | ||
9 | + | ||
10 | + dependencies = [ | ||
11 | + ('colab_gitlab', '0002_auto_20150205_1220'), | ||
12 | + ] | ||
13 | + | ||
14 | + operations = [ | ||
15 | + migrations.AlterModelOptions( | ||
16 | + name='gitlabissue', | ||
17 | + options={'verbose_name': 'Gitlab Issue', 'verbose_name_plural': 'Gitlab Issues'}, | ||
18 | + ), | ||
19 | + migrations.AddField( | ||
20 | + model_name='gitlabcomment', | ||
21 | + name='issue_comment', | ||
22 | + field=models.BooleanField(default=True), | ||
23 | + preserve_default=True, | ||
24 | + ), | ||
25 | + migrations.AddField( | ||
26 | + model_name='gitlabcomment', | ||
27 | + name='parent_id', | ||
28 | + field=models.IntegerField(null=True), | ||
29 | + preserve_default=True, | ||
30 | + ), | ||
31 | + migrations.AddField( | ||
32 | + model_name='gitlabcomment', | ||
33 | + name='project', | ||
34 | + field=models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, to='colab_gitlab.GitlabProject', null=True), | ||
35 | + preserve_default=True, | ||
36 | + ), | ||
37 | + migrations.AddField( | ||
38 | + model_name='gitlabissue', | ||
39 | + name='created_at', | ||
40 | + field=models.DateTimeField(null=True, blank=True), | ||
41 | + preserve_default=True, | ||
42 | + ), | ||
43 | + migrations.AddField( | ||
44 | + model_name='gitlabmergerequest', | ||
45 | + name='created_at', | ||
46 | + field=models.DateTimeField(null=True, blank=True), | ||
47 | + preserve_default=True, | ||
48 | + ), | ||
49 | + migrations.AddField( | ||
50 | + model_name='gitlabproject', | ||
51 | + name='path_with_namespace', | ||
52 | + field=models.TextField(null=True, blank=True), | ||
53 | + preserve_default=True, | ||
54 | + ), | ||
55 | + migrations.AlterField( | ||
56 | + model_name='gitlabcomment', | ||
57 | + name='created_at', | ||
58 | + field=models.DateTimeField(null=True, blank=True), | ||
59 | + preserve_default=True, | ||
60 | + ), | ||
61 | + ] |
@@ -0,0 +1,143 @@ | @@ -0,0 +1,143 @@ | ||
1 | +from django.db import models | ||
2 | +from django.utils.translation import ugettext_lazy as _ | ||
3 | +from colab.plugins.utils.models import Collaboration | ||
4 | +from hitcounter.models import HitCounterModelMixin | ||
5 | + | ||
6 | + | ||
7 | +class GitlabProject(models.Model, HitCounterModelMixin): | ||
8 | + | ||
9 | + id = models.IntegerField(primary_key=True) | ||
10 | + description = models.TextField() | ||
11 | + public = models.BooleanField(default=True) | ||
12 | + name = models.TextField() | ||
13 | + name_with_namespace = models.TextField() | ||
14 | + created_at = models.DateTimeField(blank=True) | ||
15 | + last_activity_at = models.DateTimeField(blank=True) | ||
16 | + path_with_namespace = models.TextField(blank=True, null=True) | ||
17 | + | ||
18 | + @property | ||
19 | + def url(self): | ||
20 | + return u'/gitlab/{}'.format(self.path_with_namespace) | ||
21 | + | ||
22 | + class Meta: | ||
23 | + verbose_name = _('Gitlab Project') | ||
24 | + verbose_name_plural = _('Gitlab Projects') | ||
25 | + | ||
26 | + | ||
27 | +class GitlabMergeRequest(Collaboration): | ||
28 | + | ||
29 | + id = models.IntegerField(primary_key=True) | ||
30 | + target_branch = models.TextField() | ||
31 | + source_branch = models.TextField() | ||
32 | + project = models.ForeignKey(GitlabProject, null=True, | ||
33 | + on_delete=models.SET_NULL) | ||
34 | + description = models.TextField() | ||
35 | + title = models.TextField() | ||
36 | + state = models.TextField() | ||
37 | + created_at = models.DateTimeField(blank=True, null=True) | ||
38 | + | ||
39 | + @property | ||
40 | + def modified(self): | ||
41 | + return self.created_at | ||
42 | + | ||
43 | + @property | ||
44 | + def tag(self): | ||
45 | + return self.state | ||
46 | + | ||
47 | + type = u'merge_request' | ||
48 | + icon_name = u'file' | ||
49 | + | ||
50 | + @property | ||
51 | + def url(self): | ||
52 | + return u'/gitlab/{}/merge_requests/{}'.format( | ||
53 | + self.project.path_with_namespace, self.id) | ||
54 | + | ||
55 | + def get_author(self): | ||
56 | + return self.user | ||
57 | + | ||
58 | + class Meta: | ||
59 | + verbose_name = _('Gitlab Merge Request') | ||
60 | + verbose_name_plural = _('Gitlab Merge Requests') | ||
61 | + | ||
62 | + | ||
63 | +class GitlabIssue(Collaboration): | ||
64 | + | ||
65 | + id = models.IntegerField(primary_key=True) | ||
66 | + project = models.ForeignKey(GitlabProject, null=True, | ||
67 | + on_delete=models.SET_NULL) | ||
68 | + title = models.TextField() | ||
69 | + description = models.TextField() | ||
70 | + | ||
71 | + state = models.TextField() | ||
72 | + created_at = models.DateTimeField(blank=True, null=True) | ||
73 | + | ||
74 | + icon_name = u'align-right' | ||
75 | + type = u'gitlab_issue' | ||
76 | + | ||
77 | + @property | ||
78 | + def modified(self): | ||
79 | + return self.created_at | ||
80 | + | ||
81 | + @property | ||
82 | + def url(self): | ||
83 | + return u'/gitlab/{}/issues/{}'.format( | ||
84 | + self.project.path_with_namespace, self.id) | ||
85 | + | ||
86 | + class Meta: | ||
87 | + verbose_name = _('Gitlab Issue') | ||
88 | + verbose_name_plural = _('Gitlab Issues') | ||
89 | + | ||
90 | + | ||
91 | +class GitlabComment(Collaboration): | ||
92 | + | ||
93 | + id = models.IntegerField(primary_key=True) | ||
94 | + body = models.TextField() | ||
95 | + created_at = models.DateTimeField(blank=True, null=True) | ||
96 | + issue_comment = models.BooleanField(default=True) | ||
97 | + | ||
98 | + project = models.ForeignKey(GitlabProject, null=True, | ||
99 | + on_delete=models.SET_NULL) | ||
100 | + | ||
101 | + parent_id = models.IntegerField(null=True) | ||
102 | + type = u'comment' | ||
103 | + | ||
104 | + @property | ||
105 | + def modified(self): | ||
106 | + return self.created_at | ||
107 | + | ||
108 | + @property | ||
109 | + def title(self): | ||
110 | + if self.issue_comment: | ||
111 | + issue = GitlabIssue.objects.get(id=self.parent_id) | ||
112 | + return issue.title | ||
113 | + else: | ||
114 | + merge_request = GitlabMergeRequest.objects.get(id=self.parent_id) | ||
115 | + return merge_request.title | ||
116 | + | ||
117 | + icon_name = u'align-right' | ||
118 | + | ||
119 | + @property | ||
120 | + def description(self): | ||
121 | + return self.body | ||
122 | + | ||
123 | + @property | ||
124 | + def tag(self): | ||
125 | + if self.issue_comment: | ||
126 | + issue = GitlabIssue.objects.get(id=self.parent_id) | ||
127 | + return issue.state | ||
128 | + else: | ||
129 | + merge_request = GitlabMergeRequest.objects.get(id=self.parent_id) | ||
130 | + return merge_request.state | ||
131 | + | ||
132 | + @property | ||
133 | + def url(self): | ||
134 | + if self.issue_comment: | ||
135 | + return u'/gitlab/{}/issues/{}#notes_{}'.format( | ||
136 | + self.project.path_with_namespace, self.parent_id, self.id) | ||
137 | + else: | ||
138 | + return u'/gitlab/{}/merge_requests/{}#notes_{}'.format( | ||
139 | + self.project.path_with_namespace, self.parent_id, self.id) | ||
140 | + | ||
141 | + class Meta: | ||
142 | + verbose_name = _('Gitlab Comments') | ||
143 | + verbose_name_plural = _('Gitlab Comments') |
@@ -0,0 +1,120 @@ | @@ -0,0 +1,120 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | + | ||
3 | +import string | ||
4 | + | ||
5 | +from haystack import indexes | ||
6 | +from haystack.utils import log as logging | ||
7 | + | ||
8 | +from .models import (GitlabProject, GitlabMergeRequest, | ||
9 | + GitlabIssue, GitlabComment) | ||
10 | + | ||
11 | + | ||
12 | +logger = logging.getLogger('haystack') | ||
13 | + | ||
14 | +# The string maketrans always return a string encoded with latin1 | ||
15 | +# http://stackoverflow.com/questions/1324067/how-do-i-get-str-translate-to-work-with-unicode-strings | ||
16 | +table = string.maketrans( | ||
17 | + string.punctuation, | ||
18 | + '.' * len(string.punctuation) | ||
19 | +).decode('latin1') | ||
20 | + | ||
21 | + | ||
22 | +class GitlabProjectIndex(indexes.SearchIndex, indexes.Indexable): | ||
23 | + text = indexes.CharField(document=True, use_template=False, stored=False) | ||
24 | + title = indexes.CharField(model_attr='name') | ||
25 | + description = indexes.CharField(model_attr='description', null=True) | ||
26 | + tag = indexes.CharField() | ||
27 | + url = indexes.CharField(model_attr='url', indexed=False) | ||
28 | + icon_name = indexes.CharField() | ||
29 | + type = indexes.CharField() | ||
30 | + created = indexes.DateTimeField(model_attr='created_at', null=True) | ||
31 | + | ||
32 | + def prepare_tag(self, obj): | ||
33 | + return "{}".format(obj.name_with_namespace.split('/')[0].strip()) | ||
34 | + | ||
35 | + def prepare_icon_name(self, obj): | ||
36 | + return u'file' | ||
37 | + | ||
38 | + def get_ful_name(self): | ||
39 | + self.objs.name | ||
40 | + | ||
41 | + def get_model(self): | ||
42 | + return GitlabProject | ||
43 | + | ||
44 | + def prepare_type(self, obj): | ||
45 | + return u'gitlab' | ||
46 | + | ||
47 | + | ||
48 | +class GitlabMergeRequestIndex(indexes.SearchIndex, indexes.Indexable): | ||
49 | + | ||
50 | + text = indexes.CharField(document=True, use_template=False, stored=False) | ||
51 | + title = indexes.CharField(model_attr='title') | ||
52 | + description = indexes.CharField(model_attr='description') | ||
53 | + tag = indexes.CharField(model_attr='state') | ||
54 | + url = indexes.CharField(model_attr='url', indexed=False) | ||
55 | + icon_name = indexes.CharField() | ||
56 | + type = indexes.CharField(model_attr='type') | ||
57 | + | ||
58 | + modified_by = indexes.CharField(model_attr='modified_by', null=True) | ||
59 | + modified_by_url = indexes.CharField(model_attr='modified_by_url', | ||
60 | + null=True) | ||
61 | + modified = indexes.DateTimeField(model_attr='created_at', null=True) | ||
62 | + | ||
63 | + def get_model(self): | ||
64 | + return GitlabMergeRequest | ||
65 | + | ||
66 | + def prepare_icon_name(self, obj): | ||
67 | + return u'file' | ||
68 | + | ||
69 | + def prepare_type(self, obj): | ||
70 | + return u'merge_request' | ||
71 | + | ||
72 | + | ||
73 | +class GitlabIssueIndex(indexes.SearchIndex, indexes.Indexable): | ||
74 | + | ||
75 | + text = indexes.CharField(document=True, use_template=False, stored=False) | ||
76 | + title = indexes.CharField(model_attr='title') | ||
77 | + description = indexes.CharField(model_attr='description') | ||
78 | + tag = indexes.CharField(model_attr='state') | ||
79 | + url = indexes.CharField(model_attr='url', indexed=False) | ||
80 | + icon_name = indexes.CharField() | ||
81 | + type = indexes.CharField(model_attr='type') | ||
82 | + | ||
83 | + modified_by = indexes.CharField(model_attr='modified_by', null=True) | ||
84 | + modified_by_url = indexes.CharField(model_attr='modified_by_url', | ||
85 | + null=True) | ||
86 | + modified = indexes.DateTimeField(model_attr='created_at', null=True) | ||
87 | + | ||
88 | + def get_model(self): | ||
89 | + return GitlabIssue | ||
90 | + | ||
91 | + def prepare_icon_name(self, obj): | ||
92 | + return u'align-right' | ||
93 | + | ||
94 | + def prepare_type(self, obj): | ||
95 | + return u'merge_request' | ||
96 | + | ||
97 | + | ||
98 | +class GitlabCommentIndex(indexes.SearchIndex, indexes.Indexable): | ||
99 | + | ||
100 | + text = indexes.CharField(document=True, use_template=False, stored=False) | ||
101 | + title = indexes.CharField(model_attr='title') | ||
102 | + description = indexes.CharField(model_attr='description') | ||
103 | + tag = indexes.CharField() | ||
104 | + url = indexes.CharField(model_attr='url', indexed=False) | ||
105 | + icon_name = indexes.CharField() | ||
106 | + type = indexes.CharField(model_attr='type') | ||
107 | + | ||
108 | + modified_by = indexes.CharField(model_attr='modified_by', null=True) | ||
109 | + modified_by_url = indexes.CharField(model_attr='modified_by_url', | ||
110 | + null=True) | ||
111 | + modified = indexes.DateTimeField(model_attr='created_at', null=True) | ||
112 | + | ||
113 | + def get_model(self): | ||
114 | + return GitlabComment | ||
115 | + | ||
116 | + def prepare_icon_name(self, obj): | ||
117 | + return u'align-right' | ||
118 | + | ||
119 | + def prepare_tag(self, obj): | ||
120 | + return obj.tag |
@@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
1 | +{% extends 'base.html' %} | ||
2 | +{% load static from staticfiles %} | ||
3 | + | ||
4 | +{% block head_css %} | ||
5 | +<style> | ||
6 | + /* Reset left and with for .modal-dialog style (like gitlab does), | ||
7 | + the bootstrap.css one makes it small */ | ||
8 | + @media screen and (min-width: 768px) { | ||
9 | + .modal-dialog { | ||
10 | + left: auto; | ||
11 | + width: auto; | ||
12 | + } | ||
13 | + } | ||
14 | + div#main-content { | ||
15 | + margin-top: 65px; | ||
16 | + } | ||
17 | + | ||
18 | + div#main-content div.container { | ||
19 | + width: 1110px; | ||
20 | + } | ||
21 | + div#main-content div.flash-container{ | ||
22 | + width: 85%; | ||
23 | + } | ||
24 | + #breadcrumbs { | ||
25 | + border: 0 !important; | ||
26 | + } | ||
27 | + | ||
28 | + #right-top-nav { | ||
29 | + margin-right: 5em !important; | ||
30 | + } | ||
31 | +</style> | ||
32 | +{% endblock %} | ||
33 | + | ||
34 | +{% block head_js %} | ||
35 | +<script type="text/javascript"> | ||
36 | + jQuery(function(){ | ||
37 | + // bootstrap.css forces .hide {display:none!important}, and this makes | ||
38 | + // gitlab .hide elements NEVER have a display:block, so | ||
39 | + // instead of editing bootstrap.css, we just removed '.hide' css class and | ||
40 | + // toggled | ||
41 | + jQuery('.hide').removeClass('hide').css('display', 'none'); | ||
42 | + | ||
43 | + // Hit the SSH clone button to select it by default | ||
44 | + jQuery(".git-clone-holder .btn:contains('SSH')").click() | ||
45 | + | ||
46 | + }); | ||
47 | +</script> | ||
48 | +<script type="text/javascript" src="{% static 'third-party/bootstrap/js/bootstrap.min.js' %}"></script> | ||
49 | +<script type="text/javascript" src="{% static 'third-party/jquery.cookie.js' %}"></script> | ||
50 | +<script>jQuery.noConflict();</script> | ||
51 | +{% endblock %} |
@@ -0,0 +1,114 @@ | @@ -0,0 +1,114 @@ | ||
1 | +""" | ||
2 | +Test User class. | ||
3 | +Objective: Test parameters, and behavior. | ||
4 | +""" | ||
5 | +from datetime import datetime | ||
6 | + | ||
7 | + | ||
8 | +from django.test import TestCase, Client | ||
9 | +from colab.accounts.models import User | ||
10 | +from colab_gitlab.models import GitlabProject, \ | ||
11 | + GitlabIssue, GitlabComment, GitlabMergeRequest | ||
12 | + | ||
13 | + | ||
14 | +class GitlabTest(TestCase): | ||
15 | + | ||
16 | + def setUp(self): | ||
17 | + self.user = self.create_user() | ||
18 | + self.client = Client() | ||
19 | + self.create_gitlab_data() | ||
20 | + | ||
21 | + super(GitlabTest, self).setUp() | ||
22 | + | ||
23 | + def tearDown(self): | ||
24 | + pass | ||
25 | + | ||
26 | + def test_data_integrity(self): | ||
27 | + self.assertEqual(GitlabProject.objects.all().count(), 1) | ||
28 | + self.assertEqual(GitlabMergeRequest.objects.all().count(), 1) | ||
29 | + self.assertEqual(GitlabIssue.objects.all().count(), 1) | ||
30 | + self.assertEqual(GitlabComment.objects.all().count(), 2) | ||
31 | + | ||
32 | + def test_project_url(self): | ||
33 | + self.assertEqual(GitlabProject.objects.get(id=1).url, | ||
34 | + '/gitlab/softwarepublico/colab') | ||
35 | + | ||
36 | + def test_merge_request_url(self): | ||
37 | + self.assertEqual(GitlabMergeRequest.objects.get(id=1).url, | ||
38 | + '/gitlab/softwarepublico/colab/merge_requests/1') | ||
39 | + | ||
40 | + def test_issue_url(self): | ||
41 | + self.assertEqual(GitlabIssue.objects.get(id=1).url, | ||
42 | + '/gitlab/softwarepublico/colab/issues/1') | ||
43 | + | ||
44 | + def test_comment_on_mr_url(self): | ||
45 | + url = '/gitlab/softwarepublico/colab/merge_requests/1#notes_1' | ||
46 | + self.assertEqual(GitlabComment.objects.get(id=1).url, url) | ||
47 | + | ||
48 | + def test_comment_on_issue_url(self): | ||
49 | + self.assertEqual(GitlabComment.objects.get(id=2).url, | ||
50 | + '/gitlab/softwarepublico/colab/issues/1#notes_2') | ||
51 | + | ||
52 | + def create_gitlab_data(self): | ||
53 | + g = GitlabProject() | ||
54 | + g.id = 1 | ||
55 | + g.name = "colab" | ||
56 | + g.name_with_namespace = "Software Public / Colab" | ||
57 | + g.path_with_namespace = "softwarepublico/colab" | ||
58 | + g.created_at = datetime.now() | ||
59 | + g.last_activity_at = datetime.now() | ||
60 | + g.save() | ||
61 | + | ||
62 | + mr = GitlabMergeRequest() | ||
63 | + mr.id = 1 | ||
64 | + mr.project = g | ||
65 | + mr.title = "Include plugin support" | ||
66 | + mr.description = "Merge request for plugin support" | ||
67 | + mr.state = "Closed" | ||
68 | + mr.created_at = datetime.now() | ||
69 | + mr.update_user(self.user.username) | ||
70 | + mr.save() | ||
71 | + | ||
72 | + i = GitlabIssue() | ||
73 | + i.id = 1 | ||
74 | + i.project = g | ||
75 | + i.title = "Issue for colab" | ||
76 | + i.description = "Issue reported to colab" | ||
77 | + i.created_at = datetime.now() | ||
78 | + i.state = "Open" | ||
79 | + i.update_user(self.user.username) | ||
80 | + i.save() | ||
81 | + | ||
82 | + c1 = GitlabComment() | ||
83 | + c1.id = 1 | ||
84 | + c1.parent_id = mr.id | ||
85 | + c1.project = g | ||
86 | + c1.body = "Comment to merge request" | ||
87 | + c1.created_at = datetime.now() | ||
88 | + c1.issue_comment = False | ||
89 | + c1.update_user(self.user.username) | ||
90 | + c1.save() | ||
91 | + | ||
92 | + c2 = GitlabComment() | ||
93 | + c2.id = 2 | ||
94 | + c2.parent_id = i.id | ||
95 | + c2.project = g | ||
96 | + c2.body = "Comment to issue" | ||
97 | + c2.created_at = datetime.now() | ||
98 | + c2.issue_comment = True | ||
99 | + c2.update_user(self.user.username) | ||
100 | + c2.save() | ||
101 | + | ||
102 | + def create_user(self): | ||
103 | + user = User() | ||
104 | + user.username = "USERtestCoLaB" | ||
105 | + user.set_password("123colab4") | ||
106 | + user.email = "usertest@colab.com.br" | ||
107 | + user.id = 1 | ||
108 | + user.twitter = "usertestcolab" | ||
109 | + user.facebook = "usertestcolab" | ||
110 | + user.first_name = "USERtestCoLaB" | ||
111 | + user.last_name = "COLAB" | ||
112 | + user.save() | ||
113 | + | ||
114 | + return user |