Show More
@@ -28,8 +28,9 import logging | |||
|
28 | 28 | import traceback |
|
29 | 29 | |
|
30 | 30 | from rhodecode.model import BaseModel |
|
31 | from rhodecode.model.db import ChangesetComment | |
|
31 | from rhodecode.model.db import ChangesetComment, User, Notification | |
|
32 | 32 | from sqlalchemy.util.compat import defaultdict |
|
33 | from rhodecode.model.notification import NotificationModel | |
|
33 | 34 | |
|
34 | 35 | log = logging.getLogger(__name__) |
|
35 | 36 | |
@@ -60,6 +61,17 class ChangesetCommentsModel(BaseModel): | |||
|
60 | 61 | |
|
61 | 62 | self.sa.add(comment) |
|
62 | 63 | self.sa.commit() |
|
64 | ||
|
65 | # make notification | |
|
66 | usr = User.get(user_id) | |
|
67 | subj = 'User %s commented on %s' % (usr.username, revision) | |
|
68 | body = text | |
|
69 | recipients = ChangesetComment.get_users(revision=revision) | |
|
70 | NotificationModel().create(created_by=user_id, subject=subj, | |
|
71 | body = body, recipients = recipients, | |
|
72 | type_ = Notification.TYPE_CHANGESET_COMMENT) | |
|
73 | ||
|
74 | ||
|
63 | 75 | return comment |
|
64 | 76 | |
|
65 | 77 | def delete(self, comment_id): |
@@ -1109,18 +1109,40 class ChangesetComment(Base, BaseModel): | |||
|
1109 | 1109 | text = Column('text', Unicode(25000), nullable=False) |
|
1110 | 1110 | modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now) |
|
1111 | 1111 | |
|
1112 | author = relationship('User') | |
|
1112 | author = relationship('User', lazy='joined') | |
|
1113 | 1113 | repo = relationship('Repository') |
|
1114 | 1114 | |
|
1115 | 1115 | |
|
1116 | @classmethod | |
|
1117 | def get_users(cls, revision): | |
|
1118 | """ | |
|
1119 | Returns user associated with this changesetComment. ie those | |
|
1120 | who actually commented | |
|
1121 | ||
|
1122 | :param cls: | |
|
1123 | :param revision: | |
|
1124 | """ | |
|
1125 | return Session.query(User)\ | |
|
1126 | .filter(cls.revision == revision)\ | |
|
1127 | .join(ChangesetComment.author).all() | |
|
1128 | ||
|
1129 | ||
|
1116 | 1130 | class Notification(Base, BaseModel): |
|
1117 | 1131 | __tablename__ = 'notifications' |
|
1118 | 1132 | __table_args__ = ({'extend_existing':True}) |
|
1133 | ||
|
1134 | TYPE_CHANGESET_COMMENT = 'cs_comment' | |
|
1135 | TYPE_MESSAGE = 'message' | |
|
1136 | TYPE_MENTION = 'mention' | |
|
1137 | ||
|
1119 | 1138 | notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True) |
|
1120 | 1139 | subject = Column('subject', Unicode(512), nullable=True) |
|
1121 | 1140 | body = Column('body', Unicode(50000), nullable=True) |
|
1141 | created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True) | |
|
1122 | 1142 | created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now) |
|
1143 | type_ = Column('type', Unicode(256)) | |
|
1123 | 1144 | |
|
1145 | create_by_user = relationship('User') | |
|
1124 | 1146 | user_notifications = relationship('UserNotification', |
|
1125 | 1147 | primaryjoin = 'Notification.notification_id==UserNotification.notification_id', |
|
1126 | 1148 | cascade = "all, delete, delete-orphan") |
@@ -1131,10 +1153,15 class Notification(Base, BaseModel): | |||
|
1131 | 1153 | .filter(UserNotification.notification == self).all()] |
|
1132 | 1154 | |
|
1133 | 1155 | @classmethod |
|
1134 | def create(cls, subject, body, recipients): | |
|
1156 | def create(cls, created_by, subject, body, recipients, type_=None): | |
|
1157 | if type_ is None: | |
|
1158 | type_ = Notification.TYPE_MESSAGE | |
|
1159 | ||
|
1135 | 1160 | notification = cls() |
|
1161 | notification.create_by_user = created_by | |
|
1136 | 1162 | notification.subject = subject |
|
1137 | 1163 | notification.body = body |
|
1164 | notification.type_ = type_ | |
|
1138 | 1165 | Session.add(notification) |
|
1139 | 1166 | for u in recipients: |
|
1140 | 1167 | u.notifications.append(notification) |
@@ -1143,10 +1170,12 class Notification(Base, BaseModel): | |||
|
1143 | 1170 | |
|
1144 | 1171 | class UserNotification(Base, BaseModel): |
|
1145 | 1172 | __tablename__ = 'user_to_notification' |
|
1146 | __table_args__ = ({'extend_existing':True}) | |
|
1173 | __table_args__ = (UniqueConstraint('user_id', 'notification_id'), | |
|
1174 | {'extend_existing':True}) | |
|
1147 | 1175 | user_to_notification_id = Column("user_to_notification_id", Integer(), nullable=False, unique=True, primary_key=True) |
|
1148 | 1176 | user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) |
|
1149 | 1177 | notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), nullable=False) |
|
1178 | read = Column('read', Boolean, default=False) | |
|
1150 | 1179 | sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None) |
|
1151 | 1180 | |
|
1152 | 1181 | user = relationship('User', single_parent=True, lazy="joined") |
@@ -38,18 +38,43 from rhodecode.model.db import Notificat | |||
|
38 | 38 | |
|
39 | 39 | class NotificationModel(BaseModel): |
|
40 | 40 | |
|
41 |
def create(self, subject, body, recipients |
|
|
41 | def create(self, created_by, subject, body, recipients, | |
|
42 | type_=Notification.TYPE_MESSAGE): | |
|
43 | """ | |
|
44 | ||
|
45 | Creates notification of given type | |
|
46 | ||
|
47 | :param created_by: int, str or User instance. User who created this | |
|
48 | notification | |
|
49 | :param subject: | |
|
50 | :param body: | |
|
51 | :param recipients: list of int, str or User objects | |
|
52 | :param type_: type of notification | |
|
53 | """ | |
|
42 | 54 | |
|
43 | 55 | if not getattr(recipients, '__iter__', False): |
|
44 | 56 | raise Exception('recipients must be a list of iterable') |
|
45 | 57 | |
|
46 | for x in recipients: | |
|
47 |
|
|
|
48 | raise Exception('recipient is not instance of %s got %s' % \ | |
|
49 | (User, type(x))) | |
|
58 | created_by_obj = created_by | |
|
59 | if not isinstance(created_by, User): | |
|
60 | created_by_obj = User.get(created_by) | |
|
50 | 61 | |
|
51 | 62 | |
|
52 | Notification.create(subject, body, recipients) | |
|
63 | recipients_objs = [] | |
|
64 | for u in recipients: | |
|
65 | if isinstance(u, User): | |
|
66 | recipients_objs.append(u) | |
|
67 | elif isinstance(u, basestring): | |
|
68 | recipients_objs.append(User.get_by_username(username=u)) | |
|
69 | elif isinstance(u, int): | |
|
70 | recipients_objs.append(User.get(u)) | |
|
71 | else: | |
|
72 | raise Exception('Unsupported recipient must be one of int,' | |
|
73 | 'str or User object') | |
|
74 | ||
|
75 | Notification.create(created_by=created_by_obj, subject=subject, | |
|
76 | body = body, recipients = recipients_objs, | |
|
77 | type_=type_) | |
|
53 | 78 | |
|
54 | 79 | |
|
55 | 80 | def get_for_user(self, user_id): |
@@ -7,6 +7,9 div.diffblock { | |||
|
7 | 7 | line-height: 100%; |
|
8 | 8 | /* new */ |
|
9 | 9 | line-height: 125%; |
|
10 | -webkit-border-radius: 6px 6px 0px 0px; | |
|
11 | -moz-border-radius: 6px 6px 0px 0px; | |
|
12 | border-radius: 6px 6px 0px 0px; | |
|
10 | 13 | } |
|
11 | 14 | |
|
12 | 15 | div.diffblock.margined{ |
@@ -19,8 +22,9 div.diffblock .code-header{ | |||
|
19 | 22 | padding:10px 0 10px 0; |
|
20 | 23 | } |
|
21 | 24 | div.diffblock .code-header div{ |
|
22 |
margin-left: |
|
|
25 | margin-left:10px; | |
|
23 | 26 | font-weight: bold; |
|
27 | font-size: 14px; | |
|
24 | 28 | } |
|
25 | 29 | div.diffblock .code-body{ |
|
26 | 30 | background: #FFFFFF; |
@@ -18,11 +18,21 | |||
|
18 | 18 | <!-- box / title --> |
|
19 | 19 | <div class="title"> |
|
20 | 20 | ${self.breadcrumbs()} |
|
21 | <ul class="links"> | |
|
22 | <li> | |
|
23 | <span style="text-transform: uppercase;"><a href="#">${_('Compose message')}</a></span> | |
|
24 | </li> | |
|
25 | </ul> | |
|
21 | 26 | </div> |
|
22 |
% |
|
|
23 |
|
|
|
27 | % if c.notifications: | |
|
28 | %for notification in c.notifications: | |
|
29 | <div class="table"> | |
|
30 | <h4>${notification.subject}</h4> | |
|
31 | <div>${h.rst(notification.body)}</div> | |
|
32 | </div> | |
|
33 | %endfor | |
|
24 | 34 | %else: |
|
25 | 35 | <div class="table">${_('No notifications here yet')}</div> |
|
26 |
%endf |
|
|
36 | %endif | |
|
27 | 37 | </div> |
|
28 | 38 | </%def> |
@@ -34,12 +34,12 | |||
|
34 | 34 | <div class="diffblock"> |
|
35 | 35 | <div class="code-header"> |
|
36 | 36 | <div> |
|
37 | ${_('Changeset')} - r${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} | |
|
38 | » <span>${h.link_to(_('raw diff'), | |
|
37 | <span>${h.link_to(_('raw diff'), | |
|
39 | 38 | h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show'))}</span> |
|
40 | 39 | » <span>${h.link_to(_('download diff'), |
|
41 | 40 | h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download'))}</span> |
|
42 | </div> | |
|
41 | <div class="comments-number" style="float:right;padding-right:5px">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div> | |
|
42 | </div> | |
|
43 | 43 | </div> |
|
44 | 44 | </div> |
|
45 | 45 | <div id="changeset_content"> |
General Comments 0
You need to be logged in to leave comments.
Login now