# HG changeset patch # User Marcin Kuzminski # Date 2011-11-23 14:36:57 # Node ID 54687aa00724400a1425c91e9dd9875a0d1cedfd # Parent cac5109ac3b6015ce571abbdd68570fdac7e9bda Tests updates, Session refactoring 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: -
+
- gravatar + gravatar
- -
${h.urlify_text(notification.subject)}
+
${h.urlify_text(notification.notification.subject)}
%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()