def user_delete(user): """Deletes a user object from the ZODB and the Search DB. Does not attempt to find items authored by the user and delete those too. """ get_user_database().remove_user(user.get_user_id()) transaction_commit(None, 'AdminDeleteUser') # moved from admin.ptl/DeleteUserForm.commit() qon.search.searchengine.notify_deleted_user(user)
def user_delete_email(user, email): """Delete a confirmed or unconfirmed e-mail. Raise KeyError if attempt to delete last e-mail. Raise ValueError if email is not in user's email list. """ get_user_database().remove_user_email(user, email) transaction_commit(user, 'UserDeleteEmail') # moved from user.ptl/UserDeleteEmailForm.commit() qon.search.searchengine.notify_edited_user(user)
def user_hit(self): """Notice the fact that the user has hit a page. """ now = datetime.utcnow() if not self.last_hit or (self.last_hit < now - self.idle_resolution): self.last_hit = now # update login for users who never sign out if not self.last_login or (self.last_login < now - self.signin_resolution): self.user_signed_in() get_user_database().user_hit(self)
def user_new(email): # create user and get the initial password in plaintext. email = _unicode_fix(email) user, password = get_user_database().new_user_from_email(email) transaction_commit(None, 'NewUser') # moved from user.ptl/NewUserForm.commit() # send email e = url_quote(email) p = url_quote(password) s = url_quote("Sign in") message = _(_new_user_message) % dict(email=email, password=password, auto_login_url=messages.login_url + "?email=" + e + "&password="******"&submit-login="******"&from_url=Y") extra_headers = ['Content-Type: text/html'] # because of the href sendmail("Welcome to ned.com", message, [email], extra_headers=extra_headers) # send pm using _live_tmpl_pm_new_user in sitedev as the template template_text = qon.util.get_page_template('pm_new_user', format='text') if template_text: message_anon_send(user, "Welcome to ned.com!", template_text, True) # add orientation page to all new users' watch lists try: orientation = get_group_database()['help'].get_wiki().pages['start_here'] user.get_watch_list().watch_item(orientation) except: pass qon.search.searchengine.notify_new_user(user) return (email, message)
def group_invite_user(user, group, email, inviter): """Invite email to join group. May raise smtplib.SMTPRecipientsRefused if server rejects email. """ if not group.is_accepted() or not group.get_members().can_manage(user): raise AccessError group.add_invitation(email, inviter) transaction_commit(inviter, 'InviteToGroup') # moved from group/form.ptl/InviteForm.commit() try: user = get_user_database().get_user_by_email(email) except KeyError: # e-mail address is not registered, send an e-mail (rather than internal message) subject=_(_email_invite_subject) % dict(group_name=group.name) body=_(_email_invite_body) % dict(email=email, home_url=messages.home_url, inviter=qon.ui.blocks.user.display_name_plain(inviter), group_name=qon.ui.blocks.group.display_name_plain(group)) sendmail(subject, body, [email]) else: message_send(inviter, user, subject=_(_message_invite_subject) % dict(group_name=group.name), body=_(_message_invite_body) % dict( email=email, inviter=qon.ui.blocks.user.display_name_plain(inviter), group_name=qon.ui.blocks.group.display_name_plain(group) ) )
def delete_all_tags(i_am_sure=False): if not i_am_sure: return # globally del get_tags_database().tags get_tags_database().tags = OOBTree.OOBTree() # global reverse mapping del get_tagged_item_database().root get_tagged_item_database().root = OOBTree.OOBTree() # for each group, ensure tags are empty for group_id, group in get_group_database().root.iteritems(): del group.tags group.tags = OOBTree.OOBTree() # for user_id, user in get_user_database().root.iteritems(): if hasattr(user, "tags"): if len(user.tags) > 0: del user.tags user.tags = OOBTree.OOBTree() # get_transaction().commit()
def most_read_items(self): """Return list of most-widely-read discussion items and user news items.""" _days_cutoff = 3 if self.__most_read_items: return self.__most_read_items items = [] # discussions for group_id, group in get_group_database().root.iteritems(): items.extend(group.blog.items_with_reader_counts()) get_connection().cacheGC() # user news for user_id, user in get_user_database().root.iteritems(): items.extend(user.blog.items_with_reader_counts()) get_connection().cacheGC() # weed out items that haven't been updated in the last 3 days # (or else this list doesn't change much, and shows very old content) cutoff_date = datetime.utcnow() - timedelta(days=_days_cutoff) items = [i for i in items if not i[1].is_deleted() and i[1].last_modified(consider_comments=True) > cutoff_date] items.sort() items = items[-self._watched_items_count:] items.reverse() self.__most_read_items = items return items
def _authenticate_user(self, login_bundle, max_age): """Return user if valid, otherwise raise Fault.""" user = get_user_database().authenticate_user( login_bundle.get('username'), login_bundle.get('passdigest'), login_bundle.get('created'), login_bundle.get('nonce'), max_age, ) if user: # require atom authentication. authenticate_user will return # user if correct plaintext password is used, which we don't want # to allow if not self.require_atom or qon.atom.valid_password_digest( user.get_password_hash(), login_bundle.get('passdigest'), login_bundle.get('created'), login_bundle.get('nonce'), max_age): # valid user, other access checks self._attempt_record_ip(user) if not user.user_agreement_accepted(): raise xmlrpclib.Fault(FAULT_INVALID_LOGIN, 'Must accept User Agreement') if user.is_disabled(): raise xmlrpclib.Fault(FAULT_INVALID_LOGIN, 'Login disabled') return user raise xmlrpclib.Fault(FAULT_INVALID_LOGIN, 'Invalid login')
def karma_given_by(user): """Return a list of all HasKarma items which have received karma from user. """ from qon.base import get_group_database, get_user_database results = [] def check_karma(item): p = item.karma_points_from(user) if p: results.append((item, p)) def check_blog_karma(blog): for i in blog.get_items(): check_karma(i) for c in i.get_all_comments(): check_karma(c) for id, u in get_user_database().root.iteritems(): check_karma(u) check_blog_karma(u.blog) for id, g in get_group_database().root.iteritems(): check_blog_karma(g.blog) for id, page in g.wiki.pages.iteritems(): check_karma(page) check_blog_karma(page.blog) return results
def upgrade_visit_all_blogs(): from base import get_group_database, get_user_database, commit_upgraded_versioneds count = 0 item_count = 0 for group_id, group in get_group_database().root.iteritems(): for item in group.get_blog().get_items(): item_count += 1 for page_name, page in group.get_wiki().pages.iteritems(): for item in page.blog.get_items(): item_count += 1 count += 1 commit_upgraded_versioneds() print "Touched %d groups, %d items, %s" % (count, item_count, group_id) count = 0 item_count = 0 for user_id, user in get_user_database().root.iteritems(): for item in user.get_blog().get_items(): item_count += 1 if count % 500 == 0: print "Touched %d users, %d items" % (count, item_count) commit_upgraded_versioneds() count += 1 commit_upgraded_versioneds()
def message_anon_send(to, subject, body, suppress_email=False): """Send an anonymous message (from admin user).""" subject = _unicode_fix(subject) body = _unicode_fix(body) admin = get_user_database().get_user('admin') message_send(admin, to, subject, body, suppress_email)
def total_users_pms (self): user_db = get_user_database() users = user_db.root.values() total_pms = 0 for user in users: total_pms += user.get_user_data().get_activity().get_total_pms_sent() return total_pms
def upgrade_minus_given_to(): """Set up __minus_given_to list in all users.""" from qon.base import get_user_database, transaction_commit for user_id, user in get_user_database().root.iteritems(): changed = 0 for id2, user2 in get_user_database().root.iteritems(): if user2.karma_points_from(user) < 0: if user2 not in user._HasKarmaBank__minus_given_to: user._HasKarmaBank__minus_given_to.append(user2) changed = 1 if changed: transaction_commit(None, 'UpgradeMinusGiven') changed = 0
def upgrade_cap_subpoints(): """Remove pending subpoints from users whose banks are capped.""" from qon.base import get_user_database, transaction_commit for user_id, user in get_user_database().root.iteritems(): if user.bank_is_capped(): if user._HasKarmaBank__subpoints > 0: user._HasKarmaBank__subpoints = 0 transaction_commit(None, 'UpgradeCapSubpoints')
def upgradeToVersion1(self): self.__plus_given_to = PersistentList() friends = self.__plus_given_to # expensive n^2 initial set up of friends list from qon.base import get_user_database for user in get_user_database().root.values(): if user.karma_points_from(self) > 0: friends.append(user)
def user_atom_id(self, login_bundle, user_id): """Given a short user id (e.g. 'u123456789') return the corresponding user's atom_tag, which is required by other API calls. """ cur_user = self._check_login(login_bundle) user = get_user_database().get_user(user_id) if user: return atom_id(user) return None
def recalculate_recent_activity(self, user): """EXPENSIVE recalculation of all recent user activity.""" import blog active_groups = get_group_database().active_groups() users = get_user_database().root.values() group_blogs = [g.blog for g in active_groups] group_wikis = [g.wiki for g in active_groups] user_blogs = [u.blog for u in users] # recent blog items recent = PersistentList([(i.date, i) for i in blog.recent_items_by_author(group_blogs, user, count=self._recent_count)]) recent.reverse() self.__recent_blog_items = recent # recent blog comments recent = PersistentList([(i.date, i, parent) for i, parent in blog.recent_comments_by_author(group_blogs, user, count=self._recent_count)]) recent.reverse() self.__recent_blog_comments = recent # recent wiki pages pages = [] for wiki in group_wikis: pages.extend([(p.watchable_last_change(), p) for p in wiki.recent_edits_by_author(user, count=self._recent_count)]) pages.reverse() self.__recent_wiki_pages = PersistentList(pages) del pages # recent wiki comments comments = [] for wiki in group_wikis: comments.extend([(c.date, c, p) for p, c in wiki.recent_comments_by_author(user, count=self._recent_count)]) comments.reverse() self.__recent_wiki_comments = PersistentList(comments) del comments # recent personal comments recent = PersistentList([(i.date, i, parent) for i, parent in blog.recent_comments_by_author(user_blogs, user, count=self._recent_count)]) recent.reverse() self.__recent_personal_comments = recent del users del active_groups del group_blogs del user_blogs
def bottom_users(self): if self.__bottom_users: return self.__bottom_users user_db = get_user_database() users = user_db.root.values() bykarma = sort_list(users, lambda x: -(x.get_karma_score()), count=self._list_count) self.__bottom_users = bykarma return self.__bottom_users
def find_over_negs(): """Return users who have given more negative feedback over the threshold.""" from qon.base import get_user_database users = [] for user_id, user in get_user_database().root.iteritems(): neg_givers = user.negative_karma_givers() for karma, giver in neg_givers: if karma <= show_neg_threshold: users.append((giver, user.get_user_id(), karma)) return users
def find_over_pos(): """Return users who have given more positive feedback over +5.""" from qon.base import get_user_database users = [] for user_id, user in get_user_database().root.iteritems(): pos_givers = user.positive_karma_givers() for karma, giver in pos_givers: if karma >= 5: users.append((giver, user.get_user_id(), karma)) return users
def biggest_bank(self): if self.__biggest_bank: return self.__biggest_bank user_db = get_user_database() users = user_db.root.values() bybank = sort_list(users, lambda x: x.get_karma_bank_balance(read_only=True), count=self._list_count) self.__biggest_bank = bybank return self.__biggest_bank
def check_items(): """Check that all reachable BlogItems have their parent_blogitem field correctly set.""" from base import get_group_database, get_user_database def check_item(): """Check if item is properly in its blog's item list.""" try: index = item.blog.item_index(item) except ValueError: print "ERROR: item /group/%s/%s not found in blog." % ( item.blog.ihb.get_user_id(), item) def check_comments(): comment_count = 0 for comment in item.get_all_comments(): if comment.parent_blogitem is not item: print "ERROR: /group/%s/%d/%d/ has invalid parent_blogitem." \ % (group_id, item_count, comment_count) comment_count += 1 count = 0 item_count = 0 for group_id, group in get_group_database().root.iteritems(): for item in group.get_blog().get_items(): item_count += 1 check_item() check_comments() for page_name, page in group.get_wiki().pages.iteritems(): for item in page.blog.get_items(): item_count += 1 check_item() check_comments() count += 1 print "Checked %d groups, %d items, %s" % (count, item_count, group_id) count = 0 item_count = 0 for user_id, user in get_user_database().root.iteritems(): for item in user.get_blog().get_items(): item_count += 1 check_item() check_comments() if count % 500 == 0: print "Checked %d users, %d items" % (count, item_count) count += 1 print "Checked %d users, %d items" % (count, item_count)
def is_member(self, user_or_email, slow=False): user = get_user_database().resolve_user(user_or_email) if not user: # user not in databse return False if slow: return self.__members.is_member(user) else: # group_db can do a faster membership check than my own list of members return self in get_group_database().member_groups(user)
def karma_total_bank(self): if self.__karma_stats.total_bank is not None: return self.__karma_stats.total_bank total = 0 for user_id, user in get_user_database().root.iteritems(): total += user.get_karma_bank_balance(read_only=True) self.__karma_stats.total_bank = total qon.log.stats_info('KarmaStats\tbank:%d' % total) return self.__karma_stats.total_bank
def report_over_pos(): from qon.base import get_user_database user_db = get_user_database() users = find_over_pos() for giver, recip, amount in users: print '%s,%s,%d,%f,%d' % ( user_db.get_user(giver).display_name().replace(',','.'), user_db.get_user(recip).display_name().replace(',','.'), amount, float(amount) / float(user_db.get_user(recip).get_karma_score()), user_db.get_user(giver).get_karma_bank_balance(), )
def karma_top_user_content(self): """Return list of top contributers sorted by net: (net, user, positive, negative).""" bynet = [(pos+neg, user_id, pos, neg) \ for user_id, (pos, neg) in \ self.__karma_stats.user_content_totals.iteritems()] bynet.sort() bynet = bynet[-self._list_count:] bynet.reverse() user_db = get_user_database() return [(tot, user_db.get_user(user_id), pos, neg) \ for tot, user_id, pos, neg in bynet]
def calc_karma_total_blogitems(self): """Compute karma totals for all discussion topics and comments.""" def process_topic(item): totals['topic_plus'] += item.karma_plus_received() totals['topic_minus'] += item.karma_minus_received() def process_comment(comment): totals['comment_plus'] += comment.karma_plus_received() totals['comment_minus'] += comment.karma_minus_received() # capture comment karma for user: a positive total and a negative total author_id = comment.author.get_user_id() score = comment.get_karma_score() if score != 0: # get current totals _tot = user_comment_karma.get(author_id, (0, 0)) if score > 0: user_comment_karma[author_id] = (_tot[0] + score, _tot[1]) elif score < 0: user_comment_karma[author_id] = (_tot[0], _tot[1] + score) totals = dict(topic_plus=0, topic_minus=0, comment_plus=0, comment_minus=0) user_comment_karma = {} for user_id, group in get_group_database().root.iteritems(): for item in group.blog.get_all_items(): process_topic(item) for comment in item.get_all_comments(): process_comment(comment) get_connection().cacheGC() # personal news for user_id, user in get_user_database().root.iteritems(): for item in user.get_blog().get_all_items(): process_topic(item) for comment in item.get_all_comments(): process_comment(comment) get_connection().cacheGC() self.__karma_stats.total_topic = (totals['topic_plus'], totals['topic_minus']) self.__karma_stats.total_comment = (totals['comment_plus'], totals['comment_minus']) qon.log.stats_info('KarmaStats\ttopic:%d,%d' % self.__karma_stats.total_topic) qon.log.stats_info('KarmaStats\tcomment:%d,%d' % self.__karma_stats.total_comment) self.__karma_stats.user_content_totals = OOBTree.OOBTree(user_comment_karma)
def karma_total_user(self): """Returns (total positive, total negative).""" if self.__karma_stats.total_user is not None: return self.__karma_stats.total_user total_plus = 0 total_minus = 0 for user_id, user in get_user_database().root.iteritems(): total_plus += user.karma_plus_received() total_minus += user.karma_minus_received() self.__karma_stats.total_user = (total_plus, total_minus) qon.log.stats_info('KarmaStats\tuser:%d,%d' % self.__karma_stats.total_user) return self.__karma_stats.total_user
def tag_item (tags, user, item_oid, group, comment = None, is_user=False): """ all tags are applied through this function, which keeps the various databases consistent with each other.""" user_id = user.get_user_id() tags = qon.tags.standardize_tags(tags) # clear out any removed tags tags_db = get_tags_database() tidb = get_tagged_item_database() if is_user: user_db = get_user_database() # what gets removed? what gets added? old_tags = tidb.get_tags(item_oid, user_id) tags_to_remove = [tag for tag in old_tags if tag not in tags] tags_to_add = [tag for tag in tags if tag not in old_tags] if tags_to_remove: # remove user from removed tags tags_db.remove_tags(tags_to_remove, item_oid, user_id) if group: group.remove_tags(tags_to_remove, item_oid, user_id) # remove the tag from the user's list too. user.remove_tags(tags_to_remove, item_oid) if is_user: user_db.remove_tags(tags_to_remove, item_oid, user_id) # # if tags_to_add: # add to the global database tags_db.tag_item(user.get_user_id(), item_oid, tags, comment) # group gets its tag information if group: group.tag_item(user_id, item_oid, tags_to_add, comment) # update the user's tag cloud user.tag_item(tags, item_oid) if is_user: user_db.tag_item(user_id, item_oid, tags_to_add, comment) # # get_transaction().commit()
def get_reverse_ips(self): """Returns BTree: ip -> [(datetime, user), ...]""" if not self.__reverse_ips or self.__deferrals.defer('reverse_ips', self._slow_update_time): self.__reverse_ips = OOBTree.OOBTree() for user_id, user in get_user_database().root.iteritems(): ips = user.get_ip_addresses().iteritems() for ip, dt in ips: if not self.__reverse_ips.has_key(ip): self.__reverse_ips[ip] = [] self.__reverse_ips[ip].append((dt, user)) return self.__reverse_ips