def unfollow(follower, followed, delay_commit=False): followed = get_member(followed) follower = get_member(follower) if not followed: raise action_error(_('unable to find followed'), code=404) if not follower: raise action_error(_('unable to find follower'), code=404) #if followed not in follower.following: # GregM: can unfollow to remove trusted invite if not follower.is_following( followed) and not follower.is_follow_trusted_inviter(followed): raise action_error(_('not currently following'), code=400) #follower.following.remove(followed) follow = Session.query(Follow).filter( Follow.member_id == followed.id).filter( Follow.follower_id == follower.id).one() Session.delete(follow) if not delay_commit: Session.commit() #invalidate_member(follower) #invalidate_member(followed) followed.send_notification( messages.follow_stop(member=follower, you=followed)) return True
def follower_distrust(followed, follower, delay_commit=False): followed = get_member(followed) follower = get_member(follower) if not followed: raise action_error(_('unable to find followed'), code=404) if not follower: raise action_error(_('unable to find follower'), code=404) if not follower.is_following(followed): raise action_error(_('not currently following'), code=400) follow = Session.query(Follow).filter( Follow.member_id == followed.id).filter( Follow.follower_id == follower.id).one() if not follow: raise action_error(_('member is not a follower'), code=404) if follow.type == 'trusted': follow.type = 'normal' elif follow.type == 'trusted_invite': raise action_error(_('follower still has pending invite'), code=400) elif follow.type == 'normal': raise action_error(_('follower was not trusted'), code=400) if not delay_commit: Session.commit() # invalidate_member(follower) # GregM: Needed? # invalidate_member(followed) # GregM: Needed? follower.send_notification( messages.follower_distrusted(member=followed, you=follower)) return True
def payment_member_remove(payment_account, member): member = get_member(member) if not member.payment_account == payment_account: return False member.payment_account = None Session.commit() return True
def payment_member_add(payment_account, member): member = get_member(member) if member.payment_account: return False member.payment_account = payment_account Session.commit() return True
def get_user_and_check_password(username, password): """ Called by account controller and/or AuthKit valid_password to return a user from local db """ try: q = Session.query(User).select_from( join(User, UserLogin, User.login_details)) q = q.filter(User.id == make_username(username)) q = q.filter(User.status == 'active') q = q.filter(UserLogin.type == 'password') q = q.filter(UserLogin.token == encode_plain_text_password(password)) return q.one() except NoResultFound: # AllanC - Added fallback to search for email as some users get confised as to how to identify themselfs # emails are not indexed? performance? using this should be safe as our username policy prohibits '@' and '.' try: q = Session.query(User).select_from( join(User, UserLogin, User.login_details)) q = q.filter(User.email == username) q = q.filter(User.status == 'active') q = q.filter(UserLogin.type == 'password') q = q.filter( UserLogin.token == encode_plain_text_password(password)) return q.one() except NoResultFound: return None
def follower_invite_trusted(followed, follower, delay_commit=False): followed = get_member(followed) follower = get_member(follower) if not followed: raise action_error(_('unable to find followed'), code=404) if not follower: raise action_error(_('unable to find follower'), code=404) if follower == followed: raise action_error(_('may not follow yourself'), code=400) #if followed in follower.following: if follower.is_following(followed): raise action_error(_('already following'), code=400) if follower.is_follow_trusted_inviter(followed): raise action_error(_('already invited to follow as trusted')) follow = Follow() follow.member = followed follow.follower = follower follow.type = 'trusted_invite' Session.add(follow) if not delay_commit: Session.commit() #invalidate_member(follower) #invalidate_member(followed) follower.send_notification( messages.follow_invite_trusted(member=followed, you=follower)) return True
def get_membership_tree(group, member, iter = 0): if iter > 5: return None member = get_member(member) group = get_group(group) if not (member and group): return None try: return Session.query(GroupMembership).filter( and_( GroupMembership.group_id == group.id, GroupMembership.member_id == member.id ) ).one() except NoResultFound: try: groups = Session.query(GroupMembership).filter( and_( GroupMembership.group_id == group.id, GroupMembership.member_id != member.id, # isinstance(GroupMembership.member, Group) ) ).all() for p_group in groups: p_result = get_membership_tree(p_group.member.id, member.id, iter + 1) if p_result: return p_result return None except NoResultFound: return None
def parent_disassociate(content, delay_commit=False): if not content.parent: return False # Update has to be done before the commit in this case bcause the parent is needed #invalidate_content(content.parent) # Could update responses in the future, but for now we just invalidate the whole content #invalidate_content(content) # this currently has code to update parents reponses, is the line above needed? if content.__type__ == 'comment': content.creator.send_notification( messages.comment_dissassociated( parentcreator=content.parent.creator, parentcontent=content.parent)) content.visible = False else: content.creator.send_notification( messages.article_disassociated_from_assignment( member=content.parent.creator, article=content, assignment=content.parent)) # TODO: what if an assignment is dissasocaited from an assignment? if content.__type__ == 'article': content.approval = "dissassociated" content.parent = None if not delay_commit: Session.commit() return True
def worker_workout(): print "worker_workout():" print '*** Session ***' print '>>> Session.query(Content).first()' print Session.query(Content).first() print '*** I18n ***' print '>>> _("This is a workout of internationalisation in the worker")' print _("This is a workout of internationalisation in the worker") print '*** Config ***' print '>>> cbutils.worker.config["debug"]' import cbutils.worker print cbutils.worker.config["debug"] print '*** Template ***' print '>>> ?' print '*** URL Generation ***' print '>>> url(controller="misc", action="about", id="civicboom")' print url(controller="misc", action="about", id="civicboom") print url(host='moo', controller="misc", action="about", id="civicboom") print url(protocol='test', host='cake', controller="misc", action="about", id="civicboom") print url(protocol='test', controller="misc", action="about", id="civicboom") print url(sub_domain='subdom', controller="misc", action="about", id="civicboom") return True
def viewable_by(self, member): """ Check to see if a member object has the rights to view this content """ # TODO check groups of creator to see if member is in the owning group if self.editable_by(member): return True # Always allow content to be viewed by owners/editors if self.__type__ == "draft": return False # if draft, only editors (above) can see if self.__type__ == "comment": return self.parent.viewable_by( member) # if comment, show if we can see the parent article if self.visible == True: # GregM: If current content has a root parent then check viewable_by on root parent root = self.root_parent if root: return root.viewable_by(member) # GregM: If content is private check member is a trusted follower of content's creator # We NEED to check has accepted, invited etc. for requests if self.private == True: if self.creator.is_follower_trusted(member): return True elif self.__type__ == "assignment": from civicboom.lib.database.get_cached import get_assigned_to member_assignment = get_assigned_to(self, member) if member_assignment: if not member_assignment.member_viewed: from civicboom.model.meta import Session member_assignment.member_viewed = True Session.commit() return True return False return True return False
def parent_approve(content, delay_commit=False): content.edit_lock = "parent_owner" content.approval = "approved" # AllanC - the direct email notifications were removed. They have now been replaced by the notification system # Email content parent & content creator #from pylons import tmpl_context as c # Needed for passing varibles to templates #c.content = content #content.parent.creator.send_email(subject=_('content request' ), content_html=render('/email/approve_lock/lock_article_to_organisation.mako')) #content.creator.send_email( subject=_('content approved'), content_html=render('/email/approve_lock/lock_article_to_member.mako')) # Generate notifications - these have custom email templates that override the base notification extra_vars = { 'content_id': content.id } #extra variables for template rendering content.creator.send_notification( messages.article_approved_creator(member=content.parent.creator, parent=content.parent, content=content), extra_vars=extra_vars) #, delay_commit=True content.parent.creator.send_notification( messages.article_approved_parent(member=content.parent.creator, parent=content.parent, content=content), extra_vars=extra_vars) #, delay_commit=True if not delay_commit: Session.commit() #invalidate_content(content) return True
def respond_assignment(parent_content, member, delay_commit=False): """ When creating a response, the accepted record should be flagged as responded """ member = get_member(member) parent_content = get_content(parent_content) if not member: raise action_error(_("cant find user"), code=404) if not parent_content: raise action_error(_("cant find parent content"), code=404) if parent_content.__type__ != 'assignment': return # Nothing to do if parent is not assignment try: # upgrade an 'accepted' record to 'responded' member_assignment = Session.query(MemberAssignment).filter_by( member_id=member.id, content_id=parent_content.id).one() member_assignment.status = "responded" except: # otherwise create 'responded' record member_assignment = MemberAssignment() member_assignment.content = parent_content member_assignment.member = member #assignment_accepted.member_id = member.id member_assignment.status = "responded" Session.add(member_assignment) if not delay_commit: Session.commit() #invalidate_accepted_assignment(member) return True
def withdraw_assignemnt(assignment, member, delay_commit=False): member = get_member(member) assignment = get_content(assignment) if not member: raise action_error(_("cant find user"), code=404) if not assignment: raise action_error(_("cant find assignment"), code=404) try: assignment_accepted = Session.query(MemberAssignment).filter_by( member_id=member.id, content_id=assignment.id, status="accepted").one() assignment_accepted.status = "withdrawn" #Session.update(assignment_accepted) Session.commit() #invalidate_accepted_assignment(member) assignment.creator.send_notification( messages.assignment_interest_withdrawn(member=member, assignment=assignment, you=assignment.creator)) return True except: pass return False
def associate_janrain_account(user, type, token): """ Associate a login record for a Janrain account This is called at: 1.) Registration 2.) Linking multiple login accounts to a single Civicboom account """ login = None try: login = Session.query(UserLogin).filter(UserLogin.token == token).filter(UserLogin.type == type).one() except: pass if login: if login.user == user: return # If login already belongs to this user then abort if login.user: # Warn existing user that account is being reallocated login.user.send_email(subject=_('login account reallocated'), content_text=_('your %s account has been allocated to the user %s') % (type, user.username)) if not config['development_mode']: janrain('unmap', identifier=login.token, primaryKey=login.member_id) login.user = user else: login = UserLogin() login.user = user login.type = type login.token = token Session.add(login) Session.commit() if not config['development_mode']: janrain('map', identifier=login.token, primaryKey=login.member_id) # Let janrain know this users primary key id, this is needed for agrigation posts
def get_media(id=None, hash=None): if id: return Session.query(Media).get(id) if hash: try: return Session.query(Media).filter_by(hash=hash).first() except NoResultFound: return None
def del_group(group): group = get_group(group) from pylons import tmpl_context as c for member in [member_role.member for member_role in group.members_roles]: member.send_notification( messages.group_deleted(group=group, admin=c.logged_in_user) ) # AllanC - We cant use the standard group.send_notification because the group wont exisit after this line! Session.delete(group) Session.commit()
def rate_content(content, member, rating): content = get_content(content) member = get_member(member) rating_value = int(rating) if not content: raise action_error(_('unable to find content'), code=404) if not member: raise action_error(_('unable to find member'), code=404) if rating and rating_value < 0 or rating_value > 5: raise action_error(_("Ratings can only be in the range 0 to 5"), code=400) # remove any existing ratings # we need to commit after removal, otherwise SQLAlchemy # will optimise remove->add as modify-existing, and the # SQL trigger will break try: existing = Session.query(Rating).filter( Rating.content == content).filter(Rating.member == member).one() Session.delete(existing) Session.commit() except NoResultFound: pass # rating = 0 = remove vote # add a new one if rating_value > 0: r = Rating() r.content = content r.member = member r.rating = rating_value Session.add(r) Session.commit()
def unboom_content(content, member, delay_commit=False): boom = has_boomed(content, member) if boom: Session.delete(boom) else: raise action_error(_( "%s has not boomed previously boomed this _content" % member), code=400) if not delay_commit: Session.commit()
def parent_seen(content, delay_commit=False): content.edit_lock = "parent_owner" content.approval = "seen" # AllanC - TODO generate notification #content.creator.send_notification(???, delay_commit=True) if not delay_commit: Session.commit() #invalidate_content(content) return True
def verify_email_hash(user, hash, commit=False): user = get_member(user) if user and user.hash() == hash: if not config['demo_mode']: # AllanC - Demo mode is ALWAYS offline, there is no way we can validate members emails address's. But the hash is correct so return True if user.email_unverified: user.email = user.email_unverified user.email_unverified = None if commit: Session.commit() return True return False
def part_pay_invoice_manual(self, invoice, amount=None): """ Create a manual transaction against invoice """ txn = BillingTransaction() txn.invoice = invoice txn.status = 'complete' txn.amount = amount or invoice.total_due txn.provider = 'manual_test' txn.reference = 'test' Session.commit() pass
def get_tag(tag): """ Returns a tag object for the string passed to it If it does not appear in the database then return a new tag object If it does exisit in the data then return the database object """ tag = tag.lower() try: return Session.query(Tag).filter_by(name=unicode(tag)).one() except NoResultFound as nrf: t = Tag(unicode(tag)) Session.add(t) return t
def delete_content(self, id, force=False): if force: # ignore logged in user and just get rid of it Session.delete(Session.query(Content).get(id)) Session.commit() else: self.assertIn('delete', self.get_actions(id)) response = self.app.post(url('content', id=id, format="json"), params={ '_method': 'delete', '_authentication_token': self.auth_token, }, status=200)
def test_delete_content(self): self.assertEqual(self.num_content_public('delete_cascade'), 0) num_content_start = self.num_content_public() # Step 1: Create content self.content_id = self.create_content(type='assignment') # Step 2: Create responses, comments and accept self.log_in_as('unitfriend') #self.accept_assignment(self.content_id) # Accepting should now be done automatically when responding response_1_id = self.create_content(parent_id=self.content_id, title='response 1', content='delete_cascade') response_2_id = self.create_content(parent_id=self.content_id, title='response 2', content='delete_cascade') self.comment(self.content_id, 'delete_cascade comment') self.comment(response_1_id, 'delete_cascade response comment') response = self.app.get(url('content', id=self.content_id, format='json'), status=200) response_json = json.loads(response.body) self.assertEqual(response_json['data']['responses']['count'], 2) self.assertEqual(response_json['data']['comments']['count'], 1) self.assertEqual(response_json['data']['accepted_status']['count'], 1) # Step 3: Delete content content_delete_cascade = get_content(self.content_id) content_delete_cascade.delete() # Step 4: Check deleted response = self.app.get(url('content', id=response_1_id, format='json'), status=200) self.assertIn('delete_cascade response comment', response) response = self.app.get(url('content', id=response_2_id, format='json'), status=200) self.assertEqual( Session.query(Content).filter_by( parent_id=self.content_id).count(), 0) self.assertEqual( Session.query(Tag).filter_by(name=u'delete_cascade').count(), 1 ) #Tag remains at the end, this could be tidyed witha delete orphan cascade self.assertEqual( Session.query(MemberAssignment).filter_by( content_id=self.content_id).count(), 0)
def _to_python(self, value, state): value = unicode(value) from pylons import tmpl_context as c if c.logged_in_persona and c.logged_in_persona.email == value: # If the current user has this email then bypass the validator return value email_count = Session.query(User).filter(User.email == value).count() if self.check_unverifyed_emails: email_count += Session.query(User).filter( User.email_unverified == value).count() if email_count > 0: raise formencode.Invalid( _('This email address is already registered with us. Please use a different address, or retrieve your password using the password recovery link.' ), value, state) return value
def get_member(member): if not member: return None if isinstance(member, Member): return member assert type(member) in [str, unicode], debug_type(member) member = make_username(member) def get_member_nocache(member_id): try: return Session.query(Member).with_polymorphic('*').get(member_id) except NoResultFound: return None cache = _cache.get('member') cache_func = lambda: get_member_nocache(member) if cache: result = cache.get(key='member:%s' % member, createfunc=cache_func) #try: #Session.add(result) #return result #except InvalidRequestError: return Session.merge(result, load=False) return cache_func()
def mark_messages_as_read(self, **kwargs): """ POST /profile/{id}/mark_messages_as_read: Mark messages as read @type action @api contents 1.0 (WIP) @param type type of message object to mark as read from all, to, notification """ list_type = kwargs.get('list', 'all') if list_type in list_filters and list_type in ['all','to','notification']: results = Session.query(Message).filter(Message.target_id==c.logged_in_persona.id) results = list_filters[list_type](results) for message in results.all(): message.read = True Session.commit() return action_ok(message='%s marked as read' % type, code=201) raise action_error(_('list %s not supported') % kwargs.get('list'), code=400)
def accept_assignment(assignment, member, status="accepted", delay_commit=False): member = get_member(member) assignment = get_content(assignment) if not member: raise action_error(_("cant find user"), code=404) if not assignment: raise action_error(_("cant find assignment"), code=404) if not issubclass(assignment.__class__, AssignmentContent): raise action_error(_("only _assignments can be accepted"), code=400) # all permissins hendled by controler action - so this is unneeded here #if not assignment.viewable_by(c.logged_in_persona): # raise action_error(_('_assignment is not visible to your user and therefor cannot be accepted'), code=403) if assignment_previously_accepted_by(assignment, member): raise action_error(_( '_assignment has been previously accepted and cannot be accepted again' ), code=400) #if assignment.creator == member: # raise action_error(_("cannot accept your own _assignment"), code=400) assignment_accepted = MemberAssignment() assignment.assigned_to.append(assignment_accepted) assignment_accepted.member = member assignment_accepted.status = status Session.add(assignment_accepted) if not delay_commit: Session.commit() #invalidate_accepted_assignment(member) if status == "accepted": assignment.creator.send_notification( messages.assignment_accepted(member=member, assignment=assignment, you=assignment.creator)) if status == "pending": member.send_notification( messages.assignment_invite(member=assignment.creator, assignment=assignment, you=member)) return True
def remove_member(group, member, delay_commit=False): group = get_group(group) member = get_member(member) membership = get_membership(group, member) if not group: raise action_error(_('unable to find group'), code=404) if not member: raise action_error(_('unable to find member'), code=404) if not membership: raise action_error(_('not a member of group'), code=400) # AllanC - permissions moved to controller #if member!=c.logged_in_persona and not group.is_admin(c.logged_in_persona): # raise action_error('current user has no permissions for this group', 403) #AllanC - integrety moved to model #if membership.role=="admin" and num_admins<=1: # raise action_error('cannot remove last admin', 400) # Notifications if membership.status == "active": # member removed from pylons import tmpl_context as c if member != c.logged_in_user: membership.member.send_notification( messages.group_remove_member_to_member(admin=c.logged_in_user, group=group)) group.send_notification( messages.group_remove_member_to_group(admin=c.logged_in_user, group=group, member=member)) elif membership.status == "invite": # invitation declined group.send_notification( messages.group_invitation_declined(member=member, group=group)) elif membership.status == "request": # request declined membership.member.send_notification( messages.group_request_declined(group=group)) Session.delete(membership) if not delay_commit: Session.commit() #invalidate_member(group) #invalidate_member(member) return True
def set_role(group, member, role, delay_commit=False): group = get_group(group) member = get_member(member) membership = get_membership(group, member) role = role or membership.role or group.default_role if not group: raise action_error(_('unable to find group'), code=404) if not member: raise action_error(_('unable to find member'), code=404) if not membership: raise action_error(_('not a member of group'), code=400) if role not in group_member_roles.enums: raise action_error('not a valid role', code=400) # AllanC - permisions moved to controller #if not group.is_admin(c.logged_in_persona): # raise action_error(_('no permissions for this group'), 403) # AllanC - integrtiy moved to model #if membership.role=="admin" and num_admins<=1: # raise action_error('cannot remove last admin', 400) from pylons import tmpl_context as c membership.role = role if membership.status == "request": membership.status = "active" member.send_notification( messages.group_request_accepted(admin=c.logged_in_user, group=group, you=member)) group.send_notification( messages.group_new_member(member=member, group=group)) else: group.send_notification( messages.group_role_changed(admin=c.logged_in_user, member=member, group=group, role=role)) if not delay_commit: Session.commit() #invalidate_member(group) #invalidate_member(member) return True