##// END OF EJS Templates
events: add serialization .to_dict() to events based on marshmallow
dan -
r379:a86e0931 default
parent child
Show More
@@ -0,0 +1,69
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
831 license = [ pkgs.lib.licenses.bsdOriginal ];
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 mccabe = super.buildPythonPackage {
847 mccabe = super.buildPythonPackage {
835 name = "mccabe-0.3";
848 name = "mccabe-0.3";
836 buildInputs = with self; [];
849 buildInputs = with self; [];
@@ -1355,7 +1368,7
1355 name = "rhodecode-enterprise-ce-4.3.0";
1368 name = "rhodecode-enterprise-ce-4.3.0";
1356 buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner];
1369 buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner];
1357 doCheck = true;
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 src = ./.;
1372 src = ./.;
1360 meta = {
1373 meta = {
1361 license = [ { fullName = "AGPLv3, and Commercial License"; } ];
1374 license = [ { fullName = "AGPLv3, and Commercial License"; } ];
@@ -1637,5 +1650,5
1637
1650
1638 ### Test requirements
1651 ### Test requirements
1639
1652
1640
1653
1641 }
1654 }
@@ -84,6 +84,7 iso8601==0.1.11
84 itsdangerous==0.24
84 itsdangerous==0.24
85 kombu==1.5.1
85 kombu==1.5.1
86 lxml==3.4.4
86 lxml==3.4.4
87 marshmallow==2.8.0
87 mccabe==0.3
88 mccabe==0.3
88 meld3==1.0.2
89 meld3==1.0.2
89 mock==1.0.1
90 mock==1.0.1
@@ -47,9 +47,14 class TestApiUpdateRepo(object):
47 ({'enable_statistics': True}, SAME_AS_UPDATES),
47 ({'enable_statistics': True}, SAME_AS_UPDATES),
48 ({'enable_locking': True}, SAME_AS_UPDATES),
48 ({'enable_locking': True}, SAME_AS_UPDATES),
49 ({'enable_downloads': True}, SAME_AS_UPDATES),
49 ({'enable_downloads': True}, SAME_AS_UPDATES),
50 ({'name': 'new_repo_name'}, {'repo_name': 'new_repo_name'}),
50 ({'name': 'new_repo_name'}, {
51 ({'group': 'test_group_for_update'},
51 'repo_name': 'new_repo_name',
52 {'repo_name': 'test_group_for_update/%s' % UPDATE_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 def test_api_update_repo(self, updates, expected, backend):
59 def test_api_update_repo(self, updates, expected, backend):
55 repo_name = UPDATE_REPO_NAME
60 repo_name = UPDATE_REPO_NAME
@@ -454,6 +454,7 class PullrequestsController(BaseRepoCon
454 h.flash(_('Successfully opened new pull request'),
454 h.flash(_('Successfully opened new pull request'),
455 category='success')
455 category='success')
456 except Exception as e:
456 except Exception as e:
457 raise
457 msg = _('Error occurred during sending pull request')
458 msg = _('Error occurred during sending pull request')
458 log.exception(msg)
459 log.exception(msg)
459 h.flash(msg, category='error')
460 h.flash(msg, category='error')
@@ -19,12 +19,6
19 from pyramid.threadlocal import get_current_registry
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 def trigger(event):
22 def trigger(event):
29 """
23 """
30 Helper method to send an event. This wraps the pyramid logic to send an
24 Helper method to send an event. This wraps the pyramid logic to send an
@@ -37,6 +31,8 def trigger(event):
37 registry.notify(event)
31 registry.notify(event)
38
32
39
33
34 from rhodecode.events.base import RhodecodeEvent
35
40 from rhodecode.events.user import (
36 from rhodecode.events.user import (
41 UserPreCreate,
37 UserPreCreate,
42 UserPreUpdate,
38 UserPreUpdate,
@@ -44,6 +40,7 from rhodecode.events.user import (
44 )
40 )
45
41
46 from rhodecode.events.repo import (
42 from rhodecode.events.repo import (
43 RepoEvent,
47 RepoPreCreateEvent, RepoCreatedEvent,
44 RepoPreCreateEvent, RepoCreatedEvent,
48 RepoPreDeleteEvent, RepoDeletedEvent,
45 RepoPreDeleteEvent, RepoDeletedEvent,
49 RepoPrePushEvent, RepoPushEvent,
46 RepoPrePushEvent, RepoPushEvent,
@@ -51,6 +48,7 from rhodecode.events.repo import (
51 )
48 )
52
49
53 from rhodecode.events.pullrequest import (
50 from rhodecode.events.pullrequest import (
51 PullRequestEvent,
54 PullRequestCreateEvent,
52 PullRequestCreateEvent,
55 PullRequestUpdateEvent,
53 PullRequestUpdateEvent,
56 PullRequestReviewEvent,
54 PullRequestReviewEvent,
@@ -16,15 +16,40
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 from marshmallow import Schema, fields
20
19 from rhodecode.events.repo import RepoEvent
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 class PullRequestEvent(RepoEvent):
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 def __init__(self, pullrequest):
53 def __init__(self, pullrequest):
29 super(PullRequestEvent, self).__init__(pullrequest.target_repo)
54 super(PullRequestEvent, self).__init__(pullrequest.target_repo)
30 self.pullrequest = pullrequest
55 self.pullrequest = pullrequest
@@ -16,8 +16,31
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 from marshmallow import Schema, fields
20
19 from rhodecode.model.db import Repository, Session
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 class RepoEvent(RhodecodeEvent):
46 class RepoEvent(RhodecodeEvent):
@@ -26,7 +49,10 class RepoEvent(RhodecodeEvent):
26
49
27 :param repo: a :class:`Repository` instance
50 :param repo: a :class:`Repository` instance
28 """
51 """
52 MarshmallowSchema = RepoEventSchema
53
29 def __init__(self, repo):
54 def __init__(self, repo):
55 super(RepoEvent, self).__init__()
30 self.repo = repo
56 self.repo = repo
31
57
32
58
@@ -73,6 +99,16 class RepoVCSEvent(RepoEvent):
73 self.extras = extras
99 self.extras = extras
74 super(RepoVCSEvent, self).__init__(self.repo)
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 class RepoPrePullEvent(RepoVCSEvent):
113 class RepoPrePullEvent(RepoVCSEvent):
78 """
114 """
@@ -17,7 +17,8
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 from zope.interface import implementer
19 from zope.interface import implementer
20 from rhodecode.events import RhodecodeEvent
20
21 from rhodecode.events.base import RhodecodeEvent
21 from rhodecode.events.interfaces import (
22 from rhodecode.events.interfaces import (
22 IUserRegistered, IUserPreCreate, IUserPreUpdate)
23 IUserRegistered, IUserPreCreate, IUserPreUpdate)
23
24
@@ -1641,6 +1641,7 class Repository(Base, BaseModel):
1641 'repo_name': repo.repo_name,
1641 'repo_name': repo.repo_name,
1642 'repo_type': repo.repo_type,
1642 'repo_type': repo.repo_type,
1643 'clone_uri': repo.clone_uri or '',
1643 'clone_uri': repo.clone_uri or '',
1644 'url': url('summary_home', repo_name=self.repo_name, qualified=True),
1644 'private': repo.private,
1645 'private': repo.private,
1645 'created_on': repo.created_on,
1646 'created_on': repo.created_on,
1646 'description': repo.description,
1647 'description': repo.description,
@@ -3112,10 +3113,9 class PullRequest(Base, _PullRequestBase
3112 merge_status = PullRequestModel().merge_status(pull_request)
3113 merge_status = PullRequestModel().merge_status(pull_request)
3113 data = {
3114 data = {
3114 'pull_request_id': pull_request.pull_request_id,
3115 'pull_request_id': pull_request.pull_request_id,
3115 'url': url('pullrequest_show',
3116 'url': url('pullrequest_show', repo_name=self.target_repo.repo_name,
3116 repo_name=pull_request.target_repo.repo_name,
3117 pull_request_id=self.pull_request_id,
3117 pull_request_id=pull_request.pull_request_id,
3118 qualified=True),
3118 qualified=True),
3119 'title': pull_request.title,
3119 'title': pull_request.title,
3120 'description': pull_request.description,
3120 'description': pull_request.description,
3121 'status': pull_request.status,
3121 'status': pull_request.status,
@@ -748,6 +748,11 class PullRequestModel(BaseModel):
748
748
749 return ids_to_add, ids_to_remove
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 def notify_reviewers(self, pull_request, reviewers_ids):
756 def notify_reviewers(self, pull_request, reviewers_ids):
752 # notification to reviewers
757 # notification to reviewers
753 if not reviewers_ids:
758 if not reviewers_ids:
@@ -141,6 +141,9 class RepoModel(BaseModel):
141
141
142 return None
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 def get_users(self, name_contains=None, limit=20, only_active=True):
147 def get_users(self, name_contains=None, limit=20, only_active=True):
145 # TODO: mikhail: move this method to the UserModel.
148 # TODO: mikhail: move this method to the UserModel.
146 query = self.sa.query(User)
149 query = self.sa.query(User)
@@ -78,6 +78,7 requirements = [
78 'ipython',
78 'ipython',
79 'iso8601',
79 'iso8601',
80 'kombu',
80 'kombu',
81 'marshmallow',
81 'msgpack-python',
82 'msgpack-python',
82 'packaging',
83 'packaging',
83 'psycopg2',
84 'psycopg2',
General Comments 0
You need to be logged in to leave comments. Login now