##// END OF EJS Templates
events: add serialization .to_dict() to events based on marshmallow
dan -
r379:a86e0931 default
parent child Browse files
Show More
@@ -0,0 +1,69 b''
1 # Copyright (C) 2016-2016 RhodeCode GmbH
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
11 #
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19 from datetime import datetime
20 from marshmallow import Schema, fields
21 from pyramid.threadlocal import get_current_request
22 from rhodecode.lib.utils2 import AttributeDict
23
24
25 SYSTEM_USER = AttributeDict(dict(
26 username='__SYSTEM__'
27 ))
28
29
30 class UserSchema(Schema):
31 """
32 Marshmallow schema for a user
33 """
34 username = fields.Str()
35
36
37 class RhodecodeEventSchema(Schema):
38 """
39 Marshmallow schema for a rhodecode event
40 """
41 utc_timestamp = fields.DateTime()
42 acting_user = fields.Nested(UserSchema)
43 acting_ip = fields.Str()
44
45
46 class RhodecodeEvent(object):
47 """
48 Base event class for all Rhodecode events
49 """
50 MarshmallowSchema = RhodecodeEventSchema
51
52 def __init__(self):
53 self.request = get_current_request()
54 self.utc_timestamp = datetime.utcnow()
55
56 @property
57 def acting_user(self):
58 if self.request:
59 return self.request.user.get_instance()
60 return SYSTEM_USER
61
62 @property
63 def acting_ip(self):
64 if self.request:
65 return self.request.user.ip_addr
66 return '<no ip available>'
67
68 def as_dict(self):
69 return self.MarshmallowSchema().dump(self).data No newline at end of file
@@ -831,6 +831,19 b''
831 831 license = [ pkgs.lib.licenses.bsdOriginal ];
832 832 };
833 833 };
834 marshmallow = super.buildPythonPackage {
835 name = "marshmallow-2.8.0";
836 buildInputs = with self; [];
837 doCheck = false;
838 propagatedBuildInputs = with self; [];
839 src = fetchurl {
840 url = "https://pypi.python.org/packages/4f/64/9393d77847d86981c84b88bbea627d30ff71b5ab1402636b366f73737817/marshmallow-2.8.0.tar.gz";
841 md5 = "204513fc123a3d9bdd7b63b9747f02e6";
842 };
843 meta = {
844 license = [ pkgs.lib.licenses.mit ];
845 };
846 };
834 847 mccabe = super.buildPythonPackage {
835 848 name = "mccabe-0.3";
836 849 buildInputs = with self; [];
@@ -1355,7 +1368,7 b''
1355 1368 name = "rhodecode-enterprise-ce-4.3.0";
1356 1369 buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner];
1357 1370 doCheck = true;
1358 propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery colander decorator docutils gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 py-gfm pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors dogpile.cache dogpile.core psutil py-bcrypt];
1371 propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery colander decorator docutils gunicorn infrae.cache ipython iso8601 kombu marshmallow msgpack-python packaging psycopg2 py-gfm pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors dogpile.cache dogpile.core psutil py-bcrypt];
1359 1372 src = ./.;
1360 1373 meta = {
1361 1374 license = [ { fullName = "AGPLv3, and Commercial License"; } ];
@@ -84,6 +84,7 b' iso8601==0.1.11'
84 84 itsdangerous==0.24
85 85 kombu==1.5.1
86 86 lxml==3.4.4
87 marshmallow==2.8.0
87 88 mccabe==0.3
88 89 meld3==1.0.2
89 90 mock==1.0.1
@@ -47,9 +47,14 b' class TestApiUpdateRepo(object):'
47 47 ({'enable_statistics': True}, SAME_AS_UPDATES),
48 48 ({'enable_locking': True}, SAME_AS_UPDATES),
49 49 ({'enable_downloads': True}, SAME_AS_UPDATES),
50 ({'name': 'new_repo_name'}, {'repo_name': 'new_repo_name'}),
51 ({'group': 'test_group_for_update'},
52 {'repo_name': 'test_group_for_update/%s' % UPDATE_REPO_NAME}),
50 ({'name': 'new_repo_name'}, {
51 'repo_name': 'new_repo_name',
52 'url': 'http://test.example.com:80/new_repo_name',
53 }),
54 ({'group': 'test_group_for_update'}, {
55 'repo_name': 'test_group_for_update/%s' % UPDATE_REPO_NAME,
56 'url': 'http://test.example.com:80/test_group_for_update/%s' % UPDATE_REPO_NAME
57 }),
53 58 ])
54 59 def test_api_update_repo(self, updates, expected, backend):
55 60 repo_name = UPDATE_REPO_NAME
@@ -454,6 +454,7 b' class PullrequestsController(BaseRepoCon'
454 454 h.flash(_('Successfully opened new pull request'),
455 455 category='success')
456 456 except Exception as e:
457 raise
457 458 msg = _('Error occurred during sending pull request')
458 459 log.exception(msg)
459 460 h.flash(msg, category='error')
@@ -19,12 +19,6 b''
19 19 from pyramid.threadlocal import get_current_registry
20 20
21 21
22 class RhodecodeEvent(object):
23 """
24 Base event class for all Rhodecode events
25 """
26
27
28 22 def trigger(event):
29 23 """
30 24 Helper method to send an event. This wraps the pyramid logic to send an
@@ -37,6 +31,8 b' def trigger(event):'
37 31 registry.notify(event)
38 32
39 33
34 from rhodecode.events.base import RhodecodeEvent
35
40 36 from rhodecode.events.user import (
41 37 UserPreCreate,
42 38 UserPreUpdate,
@@ -44,6 +40,7 b' from rhodecode.events.user import ('
44 40 )
45 41
46 42 from rhodecode.events.repo import (
43 RepoEvent,
47 44 RepoPreCreateEvent, RepoCreatedEvent,
48 45 RepoPreDeleteEvent, RepoDeletedEvent,
49 46 RepoPrePushEvent, RepoPushEvent,
@@ -51,6 +48,7 b' from rhodecode.events.repo import ('
51 48 )
52 49
53 50 from rhodecode.events.pullrequest import (
51 PullRequestEvent,
54 52 PullRequestCreateEvent,
55 53 PullRequestUpdateEvent,
56 54 PullRequestReviewEvent,
@@ -16,15 +16,40 b''
16 16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 18
19 from marshmallow import Schema, fields
20
19 21 from rhodecode.events.repo import RepoEvent
20 22
21 23
24 def get_pull_request_url(pull_request):
25 from rhodecode.model.pull_request import PullRequestModel
26 return PullRequestModel().get_url(pull_request)
27
28
29 class PullRequestSchema(Schema):
30 """
31 Marshmallow schema for a pull request
32 """
33 pull_request_id = fields.Integer()
34 url = fields.Function(get_pull_request_url)
35 title = fields.Str()
36
37
38 class PullRequestEventSchema(RepoEvent.MarshmallowSchema):
39 """
40 Marshmallow schema for a pull request event
41 """
42 pullrequest = fields.Nested(PullRequestSchema)
43
44
22 45 class PullRequestEvent(RepoEvent):
23 46 """
24 Base class for events acting on a repository.
47 Base class for pull request events.
25 48
26 :param repo: a :class:`Repository` instance
49 :param pullrequest: a :class:`PullRequest` instance
27 50 """
51 MarshmallowSchema = PullRequestEventSchema
52
28 53 def __init__(self, pullrequest):
29 54 super(PullRequestEvent, self).__init__(pullrequest.target_repo)
30 55 self.pullrequest = pullrequest
@@ -16,8 +16,31 b''
16 16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 18
19 from marshmallow import Schema, fields
20
19 21 from rhodecode.model.db import Repository, Session
20 from rhodecode.events import RhodecodeEvent
22 from rhodecode.events.base import RhodecodeEvent
23
24
25 def get_pull_request_url(repo):
26 from rhodecode.model.repo import RepoModel
27 return RepoModel().get_url(repo)
28
29
30 class RepositorySchema(Schema):
31 """
32 Marshmallow schema for a repository
33 """
34 repo_id = fields.Integer()
35 repo_name = fields.Str()
36 url = fields.Function(get_pull_request_url)
37
38
39 class RepoEventSchema(RhodecodeEvent.MarshmallowSchema):
40 """
41 Marshmallow schema for a repository event
42 """
43 repository = fields.Nested(RepositorySchema)
21 44
22 45
23 46 class RepoEvent(RhodecodeEvent):
@@ -26,7 +49,10 b' class RepoEvent(RhodecodeEvent):'
26 49
27 50 :param repo: a :class:`Repository` instance
28 51 """
52 MarshmallowSchema = RepoEventSchema
53
29 54 def __init__(self, repo):
55 super(RepoEvent, self).__init__()
30 56 self.repo = repo
31 57
32 58
@@ -73,6 +99,16 b' class RepoVCSEvent(RepoEvent):'
73 99 self.extras = extras
74 100 super(RepoVCSEvent, self).__init__(self.repo)
75 101
102 @property
103 def acting_user(self):
104 if self.extras.get('username'):
105 return User.get_by_username(extras['username'])
106
107 @property
108 def acting_ip(self):
109 if self.extras.get('ip'):
110 return User.get_by_username(extras['ip'])
111
76 112
77 113 class RepoPrePullEvent(RepoVCSEvent):
78 114 """
@@ -17,7 +17,8 b''
17 17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 18
19 19 from zope.interface import implementer
20 from rhodecode.events import RhodecodeEvent
20
21 from rhodecode.events.base import RhodecodeEvent
21 22 from rhodecode.events.interfaces import (
22 23 IUserRegistered, IUserPreCreate, IUserPreUpdate)
23 24
@@ -1641,6 +1641,7 b' class Repository(Base, BaseModel):'
1641 1641 'repo_name': repo.repo_name,
1642 1642 'repo_type': repo.repo_type,
1643 1643 'clone_uri': repo.clone_uri or '',
1644 'url': url('summary_home', repo_name=self.repo_name, qualified=True),
1644 1645 'private': repo.private,
1645 1646 'created_on': repo.created_on,
1646 1647 'description': repo.description,
@@ -3112,9 +3113,8 b' class PullRequest(Base, _PullRequestBase'
3112 3113 merge_status = PullRequestModel().merge_status(pull_request)
3113 3114 data = {
3114 3115 'pull_request_id': pull_request.pull_request_id,
3115 'url': url('pullrequest_show',
3116 repo_name=pull_request.target_repo.repo_name,
3117 pull_request_id=pull_request.pull_request_id,
3116 'url': url('pullrequest_show', repo_name=self.target_repo.repo_name,
3117 pull_request_id=self.pull_request_id,
3118 3118 qualified=True),
3119 3119 'title': pull_request.title,
3120 3120 'description': pull_request.description,
@@ -748,6 +748,11 b' class PullRequestModel(BaseModel):'
748 748
749 749 return ids_to_add, ids_to_remove
750 750
751 def get_url(self, pull_request):
752 return url('pullrequest_show', repo_name=self.target_repo.repo_name,
753 pull_request_id=self.pull_request_id,
754 qualified=True)
755
751 756 def notify_reviewers(self, pull_request, reviewers_ids):
752 757 # notification to reviewers
753 758 if not reviewers_ids:
@@ -141,6 +141,9 b' class RepoModel(BaseModel):'
141 141
142 142 return None
143 143
144 def get_url(self, repo):
145 return url('summary_home', repo_name=repo.repo_name, qualified=True)
146
144 147 def get_users(self, name_contains=None, limit=20, only_active=True):
145 148 # TODO: mikhail: move this method to the UserModel.
146 149 query = self.sa.query(User)
@@ -78,6 +78,7 b' requirements = ['
78 78 'ipython',
79 79 'iso8601',
80 80 'kombu',
81 'marshmallow',
81 82 'msgpack-python',
82 83 'packaging',
83 84 'psycopg2',
General Comments 0
You need to be logged in to leave comments. Login now