diff --git a/rhodecode/controllers/admin/notifications.py b/rhodecode/controllers/admin/notifications.py
--- a/rhodecode/controllers/admin/notifications.py
+++ b/rhodecode/controllers/admin/notifications.py
@@ -1,6 +1,7 @@
import logging
+import traceback
-from pylons import tmpl_context as c
+from pylons import tmpl_context as c, url
from rhodecode.lib.base import BaseController, render
from rhodecode.model.db import Notification
@@ -8,6 +9,8 @@ from rhodecode.model.db import Notificat
from rhodecode.model.notification import NotificationModel
from rhodecode.lib.auth import LoginRequired
from rhodecode.lib import helpers as h
+from rhodecode.model.meta import Session
+from pylons.controllers.util import redirect
log = logging.getLogger(__name__)
@@ -57,27 +60,42 @@ class NotificationsController(BaseContro
# method='delete')
# url('notification', notification_id=ID)
- no = Notification.get(notification_id)
- owner = lambda: no.notifications_to_users.user.user_id == c.rhodecode_user.user_id
- if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
- NotificationModel().delete(notification_id)
- return 'ok'
+ try:
+ no = Notification.get(notification_id)
+ owner = lambda: (no.notifications_to_users.user.user_id
+ == c.rhodecode_user.user_id)
+ if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
+ NotificationModel().delete(c.rhodecode_user.user_id, no)
+ Session.commit()
+ return 'ok'
+ except Exception:
+ Session.rollback()
+ log.error(traceback.format_exc())
return 'fail'
def show(self, notification_id, format='html'):
"""GET /_admin/notifications/id: Show a specific item"""
# url('notification', notification_id=ID)
c.user = self.rhodecode_user
- c.notification = Notification.get(notification_id)
+ no = Notification.get(notification_id)
+
+ owner = lambda: (no.notifications_to_users.user.user_id
+ == c.user.user_id)
+ if no and (h.HasPermissionAny('hg.admin', 'repository.admin')() or owner):
+ unotification = NotificationModel()\
+ .get_user_notification(c.user.user_id, no)
- unotification = NotificationModel()\
- .get_user_notification(c.user.user_id,
- c.notification)
+ # if this association to user is not valid, we don't want to show
+ # this message
+ if unotification:
+ if unotification.read is False:
+ unotification.mark_as_read()
+ Session.commit()
+ c.notification = no
- if unotification.read is False:
- unotification.mark_as_read()
+ return render('admin/notifications/show_notification.html')
- return render('admin/notifications/show_notification.html')
+ return redirect(url('notifications'))
def edit(self, notification_id, format='html'):
"""GET /_admin/notifications/id/edit: Form to edit an existing item"""
diff --git a/rhodecode/controllers/changeset.py b/rhodecode/controllers/changeset.py
--- a/rhodecode/controllers/changeset.py
+++ b/rhodecode/controllers/changeset.py
@@ -44,6 +44,7 @@ from vcs.exceptions import RepositoryErr
from vcs.nodes import FileNode
from vcs.utils import diffs as differ
from webob.exc import HTTPForbidden
+from rhodecode.model.meta import Session
log = logging.getLogger(__name__)
@@ -279,7 +280,7 @@ class ChangesetController(BaseRepoContro
revision=revision,
f_path=request.POST.get('f_path'),
line_no=request.POST.get('line'))
-
+ Session.commit()
return redirect(h.url('changeset_home', repo_name=repo_name,
revision=revision))
@@ -288,8 +289,8 @@ class ChangesetController(BaseRepoContro
co = ChangesetComment.get(comment_id)
owner = lambda : co.author.user_id == c.rhodecode_user.user_id
if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
- ccmodel = ChangesetCommentsModel()
- ccmodel.delete(comment_id=comment_id)
+ ChangesetCommentsModel().delete(comment=co)
+ Session.commit()
return True
else:
raise HTTPForbidden()
diff --git a/rhodecode/lib/__init__.py b/rhodecode/lib/__init__.py
--- a/rhodecode/lib/__init__.py
+++ b/rhodecode/lib/__init__.py
@@ -24,6 +24,7 @@
# along with this program. If not, see .
import os
+import re
def __get_lem():
from pygments import lexers
@@ -78,9 +79,9 @@ ALL_READMES = [
# extension together with weights to search lower is first
RST_EXTS = [
- ('', 0), ('.rst', 1),('.rest', 1),
- ('.RST', 2) ,('.REST', 2),
- ('.txt', 3), ('.TXT', 3)
+ ('', 0), ('.rst', 1), ('.rest', 1),
+ ('.RST', 2) , ('.REST', 2),
+ ('.txt', 3), ('.TXT', 3)
]
MARKDOWN_EXTS = [
@@ -90,7 +91,7 @@ MARKDOWN_EXTS = [
('.markdown', 4), ('.MARKDOWN', 4)
]
-PLAIN_EXTS = [('.text', 2),('.TEXT', 2)]
+PLAIN_EXTS = [('.text', 2), ('.TEXT', 2)]
ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS
@@ -223,7 +224,7 @@ def safe_str(unicode_, to_encoding='utf8
:rtype: str
:returns: str object
"""
-
+
if not isinstance(unicode_, basestring):
return str(unicode_)
@@ -436,3 +437,14 @@ def get_current_revision(quiet=False):
"was: %s" % err)
return None
+def extract_mentioned_users(s):
+ """
+ Returns unique usernames from given string s that have @mention
+
+ :param s: string to get mentions
+ """
+ usrs = {}
+ for username in re.findall(r'(?:^@|\s@)(\w+)', s):
+ usrs[username] = username
+
+ return sorted(usrs.keys())
diff --git a/rhodecode/lib/celerylib/tasks.py b/rhodecode/lib/celerylib/tasks.py
--- a/rhodecode/lib/celerylib/tasks.py
+++ b/rhodecode/lib/celerylib/tasks.py
@@ -55,8 +55,6 @@ from sqlalchemy import engine_from_confi
add_cache(config)
-
-
__all__ = ['whoosh_index', 'get_commits_stats',
'reset_user_password', 'send_email']
@@ -101,6 +99,7 @@ def get_commits_stats(repo_name, ts_min_
log.info('running task with lockkey %s', lockkey)
try:
+ sa = get_session()
lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))
#for js data compatibilty cleans the key for person from '
@@ -122,8 +121,6 @@ def get_commits_stats(repo_name, ts_min_
last_cs = None
timegetter = itemgetter('time')
- sa = get_session()
-
dbrepo = sa.query(Repository)\
.filter(Repository.repo_name == repo_name).scalar()
cur_stats = sa.query(Statistics)\
diff --git a/rhodecode/model/__init__.py b/rhodecode/model/__init__.py
--- a/rhodecode/model/__init__.py
+++ b/rhodecode/model/__init__.py
@@ -71,4 +71,22 @@ class BaseModel(object):
if sa is not None:
self.sa = sa
else:
- self.sa = meta.Session
+ self.sa = meta.Session()
+
+ def __get_instance(self, cls, instance):
+ """
+ Get's instance of given cls using some simple lookup mechanism
+
+ :param cls: class to fetch
+ :param instance: int or Instance
+ """
+
+ if isinstance(instance, cls):
+ return instance
+ elif isinstance(instance, int) or str(instance).isdigit():
+ return cls.get(instance)
+ else:
+ if instance:
+ raise Exception('given object must be int or Instance'
+ ' of %s got %s' % (type(cls),
+ type(instance)))
diff --git a/rhodecode/model/comment.py b/rhodecode/model/comment.py
--- a/rhodecode/model/comment.py
+++ b/rhodecode/model/comment.py
@@ -23,13 +23,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-import re
import logging
import traceback
from pylons.i18n.translation import _
from sqlalchemy.util.compat import defaultdict
+from rhodecode.lib import extract_mentioned_users
from rhodecode.lib import helpers as h
from rhodecode.model import BaseModel
from rhodecode.model.db import ChangesetComment, User, Repository, Notification
@@ -40,15 +40,16 @@ log = logging.getLogger(__name__)
class ChangesetCommentsModel(BaseModel):
+ def __get_changeset_comment(self, changeset_comment):
+ return self.__get_instance(ChangesetComment, changeset_comment)
def _extract_mentions(self, s):
- usrs = []
- for username in re.findall(r'(?:^@|\s@)(\w+)', s):
+ user_objects = []
+ for username in extract_mentioned_users(s):
user_obj = User.get_by_username(username, case_insensitive=True)
if user_obj:
- usrs.append(user_obj)
-
- return usrs
+ user_objects.append(user_obj)
+ return user_objects
def create(self, text, repo_id, user_id, revision, f_path=None,
line_no=None):
@@ -81,30 +82,30 @@ class ChangesetCommentsModel(BaseModel):
if line_no:
line = _('on line %s') % line_no
subj = h.link_to('Re commit: %(commit_desc)s %(line)s' % \
- {'commit_desc':desc,'line':line},
+ {'commit_desc':desc, 'line':line},
h.url('changeset_home', repo_name=repo.repo_name,
- revision = revision,
- anchor = 'comment-%s' % comment.comment_id
+ revision=revision,
+ anchor='comment-%s' % comment.comment_id
)
)
body = text
recipients = ChangesetComment.get_users(revision=revision)
recipients += self._extract_mentions(body)
NotificationModel().create(created_by=user_id, subject=subj,
- body = body, recipients = recipients,
- type_ = Notification.TYPE_CHANGESET_COMMENT)
+ body=body, recipients=recipients,
+ type_=Notification.TYPE_CHANGESET_COMMENT)
return comment
- def delete(self, comment_id):
+ def delete(self, comment):
"""
Deletes given comment
:param comment_id:
"""
- comment = ChangesetComment.get(comment_id)
+ comment = self.__get_changeset_comment(comment)
self.sa.delete(comment)
- self.sa.commit()
+
return comment
diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py
--- a/rhodecode/model/db.py
+++ b/rhodecode/model/db.py
@@ -48,7 +48,6 @@ from rhodecode.lib.caching_query import
from rhodecode.model.meta import Base, Session
-
log = logging.getLogger(__name__)
#==============================================================================
@@ -122,7 +121,7 @@ class BaseModel(object):
@classmethod
def query(cls):
- return Session.query(cls)
+ return Session().query(cls)
@classmethod
def get(cls, id_):
@@ -136,8 +135,7 @@ class BaseModel(object):
@classmethod
def delete(cls, id_):
obj = cls.query().get(id_)
- Session.delete(obj)
- Session.commit()
+ Session().delete(obj)
class RhodeCodeSetting(Base, BaseModel):
@@ -257,8 +255,8 @@ class RhodeCodeUi(Base, BaseModel):
new_ui.ui_key = key
new_ui.ui_value = val
- Session.add(new_ui)
- Session.commit()
+ Session().add(new_ui)
+ Session().commit()
class User(Base, BaseModel):
@@ -285,9 +283,7 @@ class User(Base, BaseModel):
group_member = relationship('UsersGroupMember', cascade='all')
- notifications = relationship('Notification',
- secondary='user_to_notification',
- order_by=lambda :Notification.created_on.desc())
+ notifications = relationship('UserNotification')
@property
def full_contact(self):
@@ -331,8 +327,8 @@ class User(Base, BaseModel):
"""Update user lastlogin"""
self.last_login = datetime.datetime.now()
- Session.add(self)
- Session.commit()
+ Session().add(self)
+ Session().commit()
log.debug('updated user %s lastlogin', self.username)
@@ -397,12 +393,12 @@ class UsersGroup(Base, BaseModel):
for k, v in form_data.items():
setattr(new_users_group, k, v)
- Session.add(new_users_group)
- Session.commit()
+ Session().add(new_users_group)
+ Session().commit()
return new_users_group
except:
log.error(traceback.format_exc())
- Session.rollback()
+ Session().rollback()
raise
@classmethod
@@ -414,7 +410,7 @@ class UsersGroup(Base, BaseModel):
for k, v in form_data.items():
if k == 'users_group_members':
users_group.members = []
- Session.flush()
+ Session().flush()
members_list = []
if v:
v = [v] if isinstance(v, basestring) else v
@@ -424,11 +420,11 @@ class UsersGroup(Base, BaseModel):
setattr(users_group, 'members', members_list)
setattr(users_group, k, v)
- Session.add(users_group)
- Session.commit()
+ Session().add(users_group)
+ Session().commit()
except:
log.error(traceback.format_exc())
- Session.rollback()
+ Session().rollback()
raise
@classmethod
@@ -445,11 +441,11 @@ class UsersGroup(Base, BaseModel):
assigned_groups)
users_group = cls.get(users_group_id, cache=False)
- Session.delete(users_group)
- Session.commit()
+ Session().delete(users_group)
+ Session().commit()
except:
log.error(traceback.format_exc())
- Session.rollback()
+ Session().rollback()
raise
class UsersGroupMember(Base, BaseModel):
@@ -472,8 +468,8 @@ class UsersGroupMember(Base, BaseModel):
ugm = UsersGroupMember()
ugm.users_group = group
ugm.user = user
- Session.add(ugm)
- Session.commit()
+ Session().add(ugm)
+ Session().commit()
return ugm
class Repository(Base, BaseModel):
@@ -516,7 +512,7 @@ class Repository(Base, BaseModel):
@classmethod
def get_by_repo_name(cls, repo_name):
- q = Session.query(cls).filter(cls.repo_name == repo_name)
+ q = Session().query(cls).filter(cls.repo_name == repo_name)
q = q.options(joinedload(Repository.fork))\
.options(joinedload(Repository.user))\
.options(joinedload(Repository.group))
@@ -533,7 +529,7 @@ class Repository(Base, BaseModel):
:param cls:
"""
- q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
+ q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
cls.url_sep())
q.options(FromCache("sql_cache_short", "repository_repo_path"))
return q.one().ui_value
@@ -569,7 +565,7 @@ class Repository(Base, BaseModel):
Returns base full path for that repository means where it actually
exists on a filesystem
"""
- q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
+ q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
Repository.url_sep())
q.options(FromCache("sql_cache_short", "repository_repo_path"))
return q.one().ui_value
@@ -886,10 +882,10 @@ class UserToPerm(Base, BaseModel):
new.user_id = user_id
new.permission = perm
try:
- Session.add(new)
- Session.commit()
+ Session().add(new)
+ Session().commit()
except:
- Session.rollback()
+ Session().rollback()
@classmethod
@@ -898,11 +894,12 @@ class UserToPerm(Base, BaseModel):
raise Exception('perm needs to be an instance of Permission class')
try:
- cls.query().filter(cls.user_id == user_id)\
- .filter(cls.permission == perm).delete()
- Session.commit()
+ obj = cls.query().filter(cls.user_id == user_id)\
+ .filter(cls.permission == perm).one()
+ Session().delete(obj)
+ Session().commit()
except:
- Session.rollback()
+ Session().rollback()
class UsersGroupRepoToPerm(Base, BaseModel):
__tablename__ = 'users_group_repo_to_perm'
@@ -948,10 +945,10 @@ class UsersGroupToPerm(Base, BaseModel):
new.users_group_id = users_group_id
new.permission = perm
try:
- Session.add(new)
- Session.commit()
+ Session().add(new)
+ Session().commit()
except:
- Session.rollback()
+ Session().rollback()
@classmethod
@@ -960,11 +957,12 @@ class UsersGroupToPerm(Base, BaseModel):
raise Exception('perm needs to be an instance of Permission class')
try:
- cls.query().filter(cls.users_group_id == users_group_id)\
- .filter(cls.permission == perm).delete()
- Session.commit()
+ obj = cls.query().filter(cls.users_group_id == users_group_id)\
+ .filter(cls.permission == perm).one()
+ Session().delete(obj)
+ Session().commit()
except:
- Session.rollback()
+ Session().rollback()
class UserRepoGroupToPerm(Base, BaseModel):
@@ -1077,11 +1075,11 @@ class CacheInvalidation(Base, BaseModel)
inv_obj = CacheInvalidation(key)
try:
- Session.add(inv_obj)
- Session.commit()
+ Session().add(inv_obj)
+ Session().commit()
except Exception:
log.error(traceback.format_exc())
- Session.rollback()
+ Session().rollback()
@classmethod
def set_valid(cls, key):
@@ -1090,11 +1088,11 @@ class CacheInvalidation(Base, BaseModel)
:param key:
"""
- inv_obj = Session().query(CacheInvalidation)\
+ inv_obj = CacheInvalidation.query()\
.filter(CacheInvalidation.cache_key == key).scalar()
inv_obj.cache_active = True
- Session.add(inv_obj)
- Session.commit()
+ Session().add(inv_obj)
+ Session().commit()
class ChangesetComment(Base, BaseModel):
@@ -1122,7 +1120,7 @@ class ChangesetComment(Base, BaseModel):
:param cls:
:param revision:
"""
- return Session.query(User)\
+ return Session().query(User)\
.filter(cls.revision == revision)\
.join(ChangesetComment.author).all()
@@ -1146,7 +1144,7 @@ class Notification(Base, BaseModel):
notifications_to_users = relationship('UserNotification',
primaryjoin='Notification.notification_id==UserNotification.notification_id',
lazy='joined',
- cascade = "all, delete, delete-orphan")
+ cascade="all, delete, delete-orphan")
@property
def recipients(self):
@@ -1163,9 +1161,12 @@ class Notification(Base, BaseModel):
notification.subject = subject
notification.body = body
notification.type_ = type_
- Session.add(notification)
+
for u in recipients:
- u.notifications.append(notification)
+ assoc = UserNotification()
+ assoc.notification = notification
+ u.notifications.append(assoc)
+ Session().add(notification)
return notification
@property
@@ -1177,19 +1178,17 @@ class UserNotification(Base, BaseModel):
__tablename__ = 'user_to_notification'
__table_args__ = (UniqueConstraint('user_id', 'notification_id'),
{'extend_existing':True})
- user_to_notification_id = Column("user_to_notification_id", Integer(), nullable=False, unique=True, primary_key=True)
- user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
- notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), nullable=False)
+ user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), primary_key=True)
+ notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
read = Column('read', Boolean, default=False)
sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
- user = relationship('User', single_parent=True, lazy="joined")
- notification = relationship('Notification', single_parent=True,)
+ user = relationship('User', lazy="joined")
+ notification = relationship('Notification', lazy="joined", cascade='all')
def mark_as_read(self):
self.read = True
- Session.add(self)
- Session.commit()
+ Session().add(self)
class DbMigrateVersion(Base, BaseModel):
__tablename__ = 'db_migrate_version'
diff --git a/rhodecode/model/notification.py b/rhodecode/model/notification.py
--- a/rhodecode/model/notification.py
+++ b/rhodecode/model/notification.py
@@ -88,30 +88,35 @@ class NotificationModel(BaseModel):
body=body, recipients=recipients_objs,
type_=type_)
- def delete(self, notification_id):
- # we don't want to remove actuall notification just the assignment
+ def delete(self, user, notification):
+ # we don't want to remove actual notification just the assignment
try:
- notification_id = int(notification_id)
- no = self.__get_notification(notification_id)
- if no:
- UserNotification.delete(no.notifications_to_users.user_to_notification_id)
+ notification = self.__get_notification(notification)
+ user = self.__get_user(user)
+ if notification and user:
+ obj = UserNotification.query().filter(UserNotification.user == user)\
+ .filter(UserNotification.notification == notification).one()
+ self.sa.delete(obj)
return True
except Exception:
log.error(traceback.format_exc())
raise
- def get_for_user(self, user_id):
- return User.get(user_id).notifications
+ def get_for_user(self, user):
+ user = self.__get_user(user)
+ return user.notifications
- def get_unread_cnt_for_user(self, user_id):
+ def get_unread_cnt_for_user(self, user):
+ user = self.__get_user(user)
return UserNotification.query()\
.filter(UserNotification.read == False)\
- .filter(UserNotification.user_id == user_id).count()
+ .filter(UserNotification.user == user).count()
- def get_unread_for_user(self, user_id):
+ def get_unread_for_user(self, user):
+ user = self.__get_user(user)
return [x.notification for x in UserNotification.query()\
.filter(UserNotification.read == False)\
- .filter(UserNotification.user_id == user_id).all()]
+ .filter(UserNotification.user == user).all()]
def get_user_notification(self, user, notification):
user = self.__get_user(user)
diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py
--- a/rhodecode/model/repo.py
+++ b/rhodecode/model/repo.py
@@ -300,10 +300,11 @@ class RepoModel(BaseModel):
def delete_perm_user(self, form_data, repo_name):
try:
- self.sa.query(UserRepoToPerm)\
+ obj = self.sa.query(UserRepoToPerm)\
.filter(UserRepoToPerm.repository \
== self.get_by_repo_name(repo_name))\
- .filter(UserRepoToPerm.user_id == form_data['user_id']).delete()
+ .filter(UserRepoToPerm.user_id == form_data['user_id']).one()
+ self.sa.delete(obj)
self.sa.commit()
except:
log.error(traceback.format_exc())
@@ -312,11 +313,12 @@ class RepoModel(BaseModel):
def delete_perm_users_group(self, form_data, repo_name):
try:
- self.sa.query(UsersGroupRepoToPerm)\
+ obj = self.sa.query(UsersGroupRepoToPerm)\
.filter(UsersGroupRepoToPerm.repository \
== self.get_by_repo_name(repo_name))\
.filter(UsersGroupRepoToPerm.users_group_id \
- == form_data['users_group_id']).delete()
+ == form_data['users_group_id']).one()
+ self.sa.delete(obj)
self.sa.commit()
except:
log.error(traceback.format_exc())
@@ -325,9 +327,10 @@ class RepoModel(BaseModel):
def delete_stats(self, repo_name):
try:
- self.sa.query(Statistics)\
- .filter(Statistics.repository == \
- self.get_by_repo_name(repo_name)).delete()
+ obj = self.sa.query(Statistics)\
+ .filter(Statistics.repository == \
+ self.get_by_repo_name(repo_name)).one()
+ self.sa.delete(obj)
self.sa.commit()
except:
log.error(traceback.format_exc())
diff --git a/rhodecode/model/user.py b/rhodecode/model/user.py
--- a/rhodecode/model/user.py
+++ b/rhodecode/model/user.py
@@ -353,7 +353,7 @@ class UserModel(BaseModel):
#======================================================================
# fetch default permissions
#======================================================================
- default_user = self.get_by_username('default')
+ default_user = User.get_by_username('default')
default_perms = self.sa.query(UserRepoToPerm, Repository, Permission)\
.join((Repository, UserRepoToPerm.repository_id ==
diff --git a/rhodecode/model/users_group.py b/rhodecode/model/users_group.py
--- a/rhodecode/model/users_group.py
+++ b/rhodecode/model/users_group.py
@@ -35,23 +35,14 @@ log = logging.getLogger(__name__)
class UsersGroupModel(BaseModel):
+ def __get_users_group(self, users_group):
+ return self.__get_instance(UsersGroup, users_group)
+
def get(self, users_group_id, cache = False):
- users_group = UsersGroup.query()
- if cache:
- users_group = users_group.options(FromCache("sql_cache_short",
- "get_users_group_%s" % users_group_id))
- return users_group.get(users_group_id)
+ return UsersGroup.get(users_group_id)
def get_by_name(self, name, cache = False, case_insensitive = False):
- users_group = UsersGroup.query()
- if case_insensitive:
- users_group = users_group.filter(UsersGroup.users_group_name.ilike(name))
- else:
- users_group = users_group.filter(UsersGroup.users_group_name == name)
- if cache:
- users_group = users_group.options(FromCache("sql_cache_short",
- "get_users_group_%s" % name))
- return users_group.scalar()
+ return UsersGroup.get_by_group_name(name, cache, case_insensitive)
def create(self, form_data):
try:
@@ -67,6 +58,18 @@ class UsersGroupModel(BaseModel):
self.sa.rollback()
raise
+
+ def create_(self, name, active=True):
+ new = UsersGroup()
+ new.users_group_name = name
+ new.users_group_active = active
+ self.sa.add(new)
+ return new
+
+ def delete(self, users_group):
+ obj = self.__get_users_group(users_group)
+ self.sa.delete(obj)
+
def add_user_to_group(self, users_group, user):
for m in users_group.members:
u = m.user
diff --git a/rhodecode/templates/admin/notifications/notifications.html b/rhodecode/templates/admin/notifications/notifications.html
--- a/rhodecode/templates/admin/notifications/notifications.html
+++ b/rhodecode/templates/admin/notifications/notifications.html
@@ -30,19 +30,19 @@
%>
%for notification in c.notifications:
-
+
%endfor
diff --git a/rhodecode/tests/__init__.py b/rhodecode/tests/__init__.py
--- a/rhodecode/tests/__init__.py
+++ b/rhodecode/tests/__init__.py
@@ -64,7 +64,7 @@ class TestController(TestCase):
self.app = TestApp(wsgiapp)
url._push_object(URLGenerator(config['routes.map'], environ))
- self.sa = meta.Session
+ self.Session = meta.Session
self.index_location = config['app_conf']['index_dir']
TestCase.__init__(self, *args, **kwargs)
diff --git a/rhodecode/tests/functional/test_admin_ldap_settings.py b/rhodecode/tests/functional/test_admin_ldap_settings.py
--- a/rhodecode/tests/functional/test_admin_ldap_settings.py
+++ b/rhodecode/tests/functional/test_admin_ldap_settings.py
@@ -42,6 +42,7 @@ class TestLdapSettingsController(TestCon
'ldap_attr_email':'test@example.com' })
new_settings = RhodeCodeSetting.get_ldap_settings()
+ print new_settings
self.assertEqual(new_settings['ldap_host'], u'dc.example.com',
'fail db write compare')
diff --git a/rhodecode/tests/functional/test_admin_notifications.py b/rhodecode/tests/functional/test_admin_notifications.py
--- a/rhodecode/tests/functional/test_admin_notifications.py
+++ b/rhodecode/tests/functional/test_admin_notifications.py
@@ -3,19 +3,23 @@ from rhodecode.model.db import Notificat
from rhodecode.model.user import UserModel
from rhodecode.model.notification import NotificationModel
+from rhodecode.model.meta import Session
class TestNotificationsController(TestController):
+
+ def tearDown(self):
+ for n in Notification.query().all():
+ inst = Notification.get(n.notification_id)
+ Session().delete(inst)
+ Session().commit()
+
def test_index(self):
self.log_user()
-
u1 = UserModel().create_or_update(username='u1', password='qweqwe',
email='u1@rhodecode.org',
name='u1', lastname='u1').user_id
- u2 = UserModel().create_or_update(username='u2', password='qweqwe',
- email='u2@rhodecode.org',
- name='u2', lastname='u2').user_id
response = self.app.get(url('notifications'))
self.assertTrue('''
No notifications here yet
'''
@@ -23,15 +27,12 @@ class TestNotificationsController(TestCo
cur_user = self._get_logged_user()
- NotificationModel().create(created_by=u1, subject=u'test',
+ NotificationModel().create(created_by=u1, subject=u'test_notification_1',
body=u'notification_1',
recipients=[cur_user])
+ Session().commit()
response = self.app.get(url('notifications'))
-
- self.assertTrue(u'notification_1' in response.body)
-
- User.delete(u1)
- User.delete(u2)
+ self.assertTrue(u'test_notification_1' in response.body)
# def test_index_as_xml(self):
# response = self.app.get(url('formatted_notifications', format='xml'))
@@ -62,27 +63,29 @@ class TestNotificationsController(TestCo
email='u2@rhodecode.org',
name='u2', lastname='u2')
- # make two notifications
+ # make notifications
notification = NotificationModel().create(created_by=cur_user,
subject=u'test',
body=u'hi there',
recipients=[cur_user, u1, u2])
-
+ Session().commit()
u1 = User.get(u1.user_id)
u2 = User.get(u2.user_id)
# check DB
- self.assertEqual(u1.notifications, [notification])
- self.assertEqual(u2.notifications, [notification])
+ get_notif = lambda un:[x.notification for x in un]
+ self.assertEqual(get_notif(cur_user.notifications), [notification])
+ self.assertEqual(get_notif(u1.notifications), [notification])
+ self.assertEqual(get_notif(u2.notifications), [notification])
cur_usr_id = cur_user.user_id
- response = self.app.delete(url('notification',
- notification_id=cur_usr_id))
+
- cur_user = self._get_logged_user()
- self.assertEqual(cur_user.notifications, [])
+ response = self.app.delete(url('notification',
+ notification_id=
+ notification.notification_id))
- User.delete(u1.user_id)
- User.delete(u2.user_id)
+ cur_user = User.get(cur_usr_id)
+ self.assertEqual(cur_user.notifications, [])
# def test_delete_browser_fakeout(self):
@@ -100,7 +103,7 @@ class TestNotificationsController(TestCo
notification = NotificationModel().create(created_by=cur_user,
subject='test',
- body='hi there',
+ body=u'hi there',
recipients=[cur_user, u1, u2])
response = self.app.get(url('notification',
@@ -114,4 +117,3 @@ class TestNotificationsController(TestCo
#
# def test_edit_as_xml(self):
# response = self.app.get(url('formatted_edit_notification', notification_id=1, format='xml'))
-
diff --git a/rhodecode/tests/functional/test_admin_repos.py b/rhodecode/tests/functional/test_admin_repos.py
--- a/rhodecode/tests/functional/test_admin_repos.py
+++ b/rhodecode/tests/functional/test_admin_repos.py
@@ -36,7 +36,7 @@ class TestAdminReposController(TestContr
self.checkSessionFlash(response, 'created repository %s' % (repo_name))
#test if the repo was created in the database
- new_repo = self.sa.query(Repository).filter(Repository.repo_name ==
+ new_repo = self.Session().query(Repository).filter(Repository.repo_name ==
repo_name).one()
self.assertEqual(new_repo.repo_name, repo_name)
@@ -73,7 +73,7 @@ class TestAdminReposController(TestContr
'created repository %s' % (repo_name_unicode))
#test if the repo was created in the database
- new_repo = self.sa.query(Repository).filter(Repository.repo_name ==
+ new_repo = self.Session().query(Repository).filter(Repository.repo_name ==
repo_name_unicode).one()
self.assertEqual(new_repo.repo_name, repo_name_unicode)
@@ -113,7 +113,7 @@ class TestAdminReposController(TestContr
assert '''created repository %s''' % (repo_name) in response.session['flash'][0], 'No flash message about new repo'
#test if the fork was created in the database
- new_repo = self.sa.query(Repository).filter(Repository.repo_name == repo_name).one()
+ new_repo = self.Session().query(Repository).filter(Repository.repo_name == repo_name).one()
assert new_repo.repo_name == repo_name, 'wrong name of repo name in db'
assert new_repo.description == description, 'wrong description'
@@ -162,7 +162,7 @@ class TestAdminReposController(TestContr
response.session['flash'][0])
#test if the repo was created in the database
- new_repo = self.sa.query(Repository).filter(Repository.repo_name ==
+ new_repo = self.Session().query(Repository).filter(Repository.repo_name ==
repo_name).one()
self.assertEqual(new_repo.repo_name, repo_name)
@@ -182,7 +182,7 @@ class TestAdminReposController(TestContr
response.follow()
#check if repo was deleted from db
- deleted_repo = self.sa.query(Repository).filter(Repository.repo_name
+ deleted_repo = self.Session().query(Repository).filter(Repository.repo_name
== repo_name).scalar()
self.assertEqual(deleted_repo, None)
diff --git a/rhodecode/tests/functional/test_admin_settings.py b/rhodecode/tests/functional/test_admin_settings.py
--- a/rhodecode/tests/functional/test_admin_settings.py
+++ b/rhodecode/tests/functional/test_admin_settings.py
@@ -145,7 +145,7 @@ class TestAdminSettingsController(TestCo
response.follow()
assert 'Your account was updated successfully' in response.session['flash'][0][1], 'no flash message about success of change'
- user = self.sa.query(User).filter(User.username == 'test_admin').one()
+ user = self.Session().query(User).filter(User.username == 'test_admin').one()
assert user.email == new_email , 'incorrect user email after update got %s vs %s' % (user.email, new_email)
assert user.name == new_name, 'updated field mismatch %s vs %s' % (user.name, new_name)
assert user.lastname == new_lastname, 'updated field mismatch %s vs %s' % (user.lastname, new_lastname)
@@ -171,7 +171,7 @@ class TestAdminSettingsController(TestCo
self.checkSessionFlash(response,
'Your account was updated successfully')
- user = self.sa.query(User).filter(User.username == 'test_admin').one()
+ user = self.Session().query(User).filter(User.username == 'test_admin').one()
assert user.email == old_email , 'incorrect user email after update got %s vs %s' % (user.email, old_email)
assert user.email == old_email , 'incorrect user email after update got %s vs %s' % (user.email, old_email)
diff --git a/rhodecode/tests/functional/test_admin_users.py b/rhodecode/tests/functional/test_admin_users.py
--- a/rhodecode/tests/functional/test_admin_users.py
+++ b/rhodecode/tests/functional/test_admin_users.py
@@ -32,7 +32,7 @@ class TestAdminUsersController(TestContr
assert '''created user %s''' % (username) in response.session['flash'][0], 'No flash message about new user'
- new_user = self.sa.query(User).filter(User.username == username).one()
+ new_user = self.Session().query(User).filter(User.username == username).one()
assert new_user.username == username, 'wrong info about username'
@@ -66,7 +66,7 @@ class TestAdminUsersController(TestContr
assert """
An email address must contain a single @""" in response.body
def get_user():
- self.sa.query(User).filter(User.username == username).one()
+ self.Session().query(User).filter(User.username == username).one()
self.assertRaises(NoResultFound, get_user), 'found user in database'
@@ -100,7 +100,7 @@ class TestAdminUsersController(TestContr
response = response.follow()
- new_user = self.sa.query(User).filter(User.username == username).one()
+ new_user = self.Session().query(User).filter(User.username == username).one()
response = self.app.delete(url('user', id=new_user.user_id))
assert """successfully deleted user""" in response.session['flash'][0], 'No info about user deletion'
diff --git a/rhodecode/tests/functional/test_admin_users_groups.py b/rhodecode/tests/functional/test_admin_users_groups.py
--- a/rhodecode/tests/functional/test_admin_users_groups.py
+++ b/rhodecode/tests/functional/test_admin_users_groups.py
@@ -52,13 +52,13 @@ class TestAdminUsersGroupsController(Tes
'created users group %s' % users_group_name)
- gr = self.sa.query(UsersGroup)\
+ gr = self.Session().query(UsersGroup)\
.filter(UsersGroup.users_group_name ==
users_group_name).one()
response = self.app.delete(url('users_group', id=gr.users_group_id))
- gr = self.sa.query(UsersGroup)\
+ gr = self.Session().query(UsersGroup)\
.filter(UsersGroup.users_group_name ==
users_group_name).scalar()
diff --git a/rhodecode/tests/functional/test_journal.py b/rhodecode/tests/functional/test_journal.py
--- a/rhodecode/tests/functional/test_journal.py
+++ b/rhodecode/tests/functional/test_journal.py
@@ -16,10 +16,10 @@ class TestJournalController(TestControll
def test_stop_following_repository(self):
session = self.log_user()
-# usr = self.sa.query(User).filter(User.username == 'test_admin').one()
-# repo = self.sa.query(Repository).filter(Repository.repo_name == HG_REPO).one()
+# usr = self.Session().query(User).filter(User.username == 'test_admin').one()
+# repo = self.Session().query(Repository).filter(Repository.repo_name == HG_REPO).one()
#
-# followings = self.sa.query(UserFollowing)\
+# followings = self.Session().query(UserFollowing)\
# .filter(UserFollowing.user == usr)\
# .filter(UserFollowing.follows_repository == repo).all()
#
diff --git a/rhodecode/tests/functional/test_login.py b/rhodecode/tests/functional/test_login.py
--- a/rhodecode/tests/functional/test_login.py
+++ b/rhodecode/tests/functional/test_login.py
@@ -192,7 +192,7 @@ class TestLoginController(TestController
self.assertEqual(response.status , '302 Found')
assert 'You have successfully registered into rhodecode' in response.session['flash'][0], 'No flash message about user registration'
- ret = self.sa.query(User).filter(User.username == 'test_regular4').one()
+ ret = self.Session().query(User).filter(User.username == 'test_regular4').one()
assert ret.username == username , 'field mismatch %s %s' % (ret.username, username)
assert check_password(password, ret.password) == True , 'password mismatch'
assert ret.email == email , 'field mismatch %s %s' % (ret.email, email)
@@ -224,8 +224,8 @@ class TestLoginController(TestController
new.name = name
new.lastname = lastname
new.api_key = generate_api_key(username)
- self.sa.add(new)
- self.sa.commit()
+ self.Session().add(new)
+ self.Session().commit()
response = self.app.post(url(controller='login',
action='password_reset'),
diff --git a/rhodecode/tests/functional/test_settings.py b/rhodecode/tests/functional/test_settings.py
--- a/rhodecode/tests/functional/test_settings.py
+++ b/rhodecode/tests/functional/test_settings.py
@@ -32,7 +32,7 @@ class TestSettingsController(TestControl
% (repo_name, fork_name) in response.session['flash'][0], 'No flash message about fork'
#test if the fork was created in the database
- fork_repo = self.sa.query(Repository).filter(Repository.repo_name == fork_name).one()
+ fork_repo = self.Session().query(Repository).filter(Repository.repo_name == fork_name).one()
assert fork_repo.repo_name == fork_name, 'wrong name of repo name in new db fork repo'
assert fork_repo.fork.repo_name == repo_name, 'wrong fork parrent'
diff --git a/rhodecode/tests/functional/test_summary.py b/rhodecode/tests/functional/test_summary.py
--- a/rhodecode/tests/functional/test_summary.py
+++ b/rhodecode/tests/functional/test_summary.py
@@ -43,5 +43,5 @@ class TestSummaryController(TestControll
def _enable_stats(self):
r = Repository.get_by_repo_name(HG_REPO)
r.enable_statistics = True
- self.sa.add(r)
- self.sa.commit()
+ self.Session().add(r)
+ self.Session().commit()
diff --git a/rhodecode/tests/test_libs.py b/rhodecode/tests/test_libs.py
--- a/rhodecode/tests/test_libs.py
+++ b/rhodecode/tests/test_libs.py
@@ -103,3 +103,14 @@ class TestLibs(unittest.TestCase):
for case in test_cases:
self.assertEqual(str2bool(case[0]), case[1])
+
+ def test_mention_extractor(self):
+ from rhodecode.lib import extract_mentioned_users
+ sample = ("@first hi there @marcink here's my email marcin@email.com "
+ "@lukaszb check it pls @ ttwelve @D[] @one@two@three "
+ "@MARCIN @maRCiN @2one_more22")
+ s = ['2one_more22', 'D', 'MARCIN', 'first', 'lukaszb',
+ 'maRCiN', 'marcink', 'one']
+ self.assertEqual(s, extract_mentioned_users(sample))
+
+
diff --git a/rhodecode/tests/test_models.py b/rhodecode/tests/test_models.py
--- a/rhodecode/tests/test_models.py
+++ b/rhodecode/tests/test_models.py
@@ -4,13 +4,14 @@ from rhodecode.tests import *
from rhodecode.model.repos_group import ReposGroupModel
from rhodecode.model.repo import RepoModel
-from rhodecode.model.db import RepoGroup, User, Notification, UserNotification
+from rhodecode.model.db import RepoGroup, User, Notification, UserNotification, \
+ UsersGroup, UsersGroupMember
from sqlalchemy.exc import IntegrityError
from rhodecode.model.user import UserModel
-from rhodecode.model import meta
-
-Session = meta.Session()
+from rhodecode.model.meta import Session
+from rhodecode.model.notification import NotificationModel
+from rhodecode.model.users_group import UsersGroupModel
class TestReposGroups(unittest.TestCase):
@@ -155,67 +156,108 @@ class TestReposGroups(unittest.TestCase)
# test repo
self.assertEqual(r.repo_name, os.path.join('g2', 'g1', r.just_name))
+class TestUser(unittest.TestCase):
+
+ def test_create_and_remove(self):
+ usr = UserModel().create_or_update(username=u'test_user', password=u'qweqwe',
+ email=u'u232@rhodecode.org',
+ name=u'u1', lastname=u'u1')
+ self.assertEqual(User.get_by_username(u'test_user'), usr)
+
+ # make users group
+ users_group = UsersGroupModel().create_('some_example_group')
+ Session().commit()
+ UsersGroupModel().add_user_to_group(users_group, usr)
+
+ self.assertEqual(UsersGroup.get(users_group.users_group_id), users_group)
+ self.assertEqual(UsersGroupMember.query().count(), 1)
+ UserModel().delete(usr.user_id)
+
+ self.assertEqual(UsersGroupMember.query().all(), [])
+
class TestNotifications(unittest.TestCase):
-
+ def __init__(self, methodName='runTest'):
+ self.u1 = UserModel().create_or_update(username=u'u1',
+ password=u'qweqwe',
+ email=u'u1@rhodecode.org',
+ name=u'u1', lastname=u'u1').user_id
+ self.u2 = UserModel().create_or_update(username=u'u2',
+ password=u'qweqwe',
+ email=u'u2@rhodecode.org',
+ name=u'u2', lastname=u'u3').user_id
+ self.u3 = UserModel().create_or_update(username=u'u3',
+ password=u'qweqwe',
+ email=u'u3@rhodecode.org',
+ name=u'u3', lastname=u'u3').user_id
+ super(TestNotifications, self).__init__(methodName=methodName)
- def setUp(self):
- self.u1 = UserModel().create_or_update(username=u'u1', password=u'qweqwe',
- email=u'u1@rhodecode.org',
- name=u'u1', lastname=u'u1')
- self.u2 = UserModel().create_or_update(username=u'u2', password=u'qweqwe',
- email=u'u2@rhodecode.org',
- name=u'u2', lastname=u'u3')
- self.u3 = UserModel().create_or_update(username=u'u3', password=u'qweqwe',
- email=u'u3@rhodecode.org',
- name=u'u3', lastname=u'u3')
- def tearDown(self):
- User.delete(self.u1.user_id)
- User.delete(self.u2.user_id)
- User.delete(self.u3.user_id)
+ def _clean_notifications(self):
+ for n in Notification.query().all():
+ Session().delete(n)
+
+ Session().commit()
+ self.assertEqual(Notification.query().all(), [])
def test_create_notification(self):
+ self.assertEqual([], Notification.query().all())
+ self.assertEqual([], UserNotification.query().all())
+
usrs = [self.u1, self.u2]
- notification = Notification.create(created_by=self.u1,
+ notification = NotificationModel().create(created_by=self.u1,
subject=u'subj', body=u'hi there',
recipients=usrs)
- Session.commit()
-
-
+ Session().commit()
+ u1 = User.get(self.u1)
+ u2 = User.get(self.u2)
+ u3 = User.get(self.u3)
notifications = Notification.query().all()
self.assertEqual(len(notifications), 1)
unotification = UserNotification.query()\
.filter(UserNotification.notification == notification).all()
- self.assertEqual(notifications[0].recipients, [self.u1, self.u2])
+ self.assertEqual(notifications[0].recipients, [u1, u2])
self.assertEqual(notification.notification_id,
notifications[0].notification_id)
self.assertEqual(len(unotification), len(usrs))
- self.assertEqual([x.user.user_id for x in unotification],
- [x.user_id for x in usrs])
+ self.assertEqual([x.user.user_id for x in unotification], usrs)
+
+ self._clean_notifications()
def test_user_notifications(self):
- notification1 = Notification.create(created_by=self.u1,
- subject=u'subj', body=u'hi there',
+ self.assertEqual([], Notification.query().all())
+ self.assertEqual([], UserNotification.query().all())
+
+ notification1 = NotificationModel().create(created_by=self.u1,
+ subject=u'subj', body=u'hi there1',
recipients=[self.u3])
- notification2 = Notification.create(created_by=self.u1,
- subject=u'subj', body=u'hi there',
+ Session().commit()
+ notification2 = NotificationModel().create(created_by=self.u1,
+ subject=u'subj', body=u'hi there2',
recipients=[self.u3])
- self.assertEqual(self.u3.notifications, [notification1, notification2])
+ Session().commit()
+ u3 = Session().query(User).get(self.u3)
+
+ self.assertEqual(sorted([x.notification for x in u3.notifications]),
+ sorted([notification2, notification1]))
+ self._clean_notifications()
def test_delete_notifications(self):
- notification = Notification.create(created_by=self.u1,
+ self.assertEqual([], Notification.query().all())
+ self.assertEqual([], UserNotification.query().all())
+
+ notification = NotificationModel().create(created_by=self.u1,
subject=u'title', body=u'hi there3',
recipients=[self.u3, self.u1, self.u2])
- Session.commit()
+ Session().commit()
notifications = Notification.query().all()
self.assertTrue(notification in notifications)
Notification.delete(notification.notification_id)
- Session.commit()
+ Session().commit()
notifications = Notification.query().all()
self.assertFalse(notification in notifications)
@@ -223,3 +265,65 @@ class TestNotifications(unittest.TestCas
un = UserNotification.query().filter(UserNotification.notification
== notification).all()
self.assertEqual(un, [])
+
+ self._clean_notifications()
+ def test_delete_association(self):
+
+ self.assertEqual([], Notification.query().all())
+ self.assertEqual([], UserNotification.query().all())
+
+ notification = NotificationModel().create(created_by=self.u1,
+ subject=u'title', body=u'hi there3',
+ recipients=[self.u3, self.u1, self.u2])
+ Session().commit()
+
+ unotification = UserNotification.query()\
+ .filter(UserNotification.notification ==
+ notification)\
+ .filter(UserNotification.user_id == self.u3)\
+ .scalar()
+
+ self.assertEqual(unotification.user_id, self.u3)
+
+ NotificationModel().delete(self.u3,
+ notification.notification_id)
+ Session().commit()
+
+ unotification = UserNotification.query()\
+ .filter(UserNotification.notification ==
+ notification)\
+ .filter(UserNotification.user_id == self.u3)\
+ .scalar()
+
+ self.assertEqual(unotification, None)
+ self._clean_notifications()
+
+ def test_notification_counter(self):
+ self._clean_notifications()
+ self.assertEqual([], Notification.query().all())
+ self.assertEqual([], UserNotification.query().all())
+
+ NotificationModel().create(created_by=self.u1,
+ subject=u'title', body=u'hi there_delete',
+ recipients=[self.u3, self.u1])
+ Session().commit()
+
+ self.assertEqual(NotificationModel()
+ .get_unread_cnt_for_user(self.u1), 1)
+ self.assertEqual(NotificationModel()
+ .get_unread_cnt_for_user(self.u2), 0)
+ self.assertEqual(NotificationModel()
+ .get_unread_cnt_for_user(self.u3), 1)
+
+ notification = NotificationModel().create(created_by=self.u1,
+ subject=u'title', body=u'hi there3',
+ recipients=[self.u3, self.u1, self.u2])
+ Session().commit()
+
+ self.assertEqual(NotificationModel()
+ .get_unread_cnt_for_user(self.u1), 2)
+ self.assertEqual(NotificationModel()
+ .get_unread_cnt_for_user(self.u2), 1)
+ self.assertEqual(NotificationModel()
+ .get_unread_cnt_for_user(self.u3), 2)
+ self._clean_notifications()