def toggle_love(request, next=None): """ Toggle love. """ data = request.POST.copy() next = data.get("next", next) content_type = data.get("content_type") object_pk = data.get("object_pk") if content_type == None or object_pk == None: return Http404("No object specified.") try: model = models.get_model(*content_type.split(".", 1)) target = model.objects.get(pk=object_pk) except: return Http404("An error occured trying to get the target object.") form = ToggleLoveForm(target, data=data) if form.security_errors(): def escape(s): return s.replace("<", "<").replace(">", ">") return Http404("Form failed security verification:" % escape(str(form.security_errors()))) # first filter on the object itself filters = form.get_filter_kwargs() # either add a user or a session key to our list of filters if request.user.is_authenticated(): filters['user'] = request.user else: filters['session_key'] = request.session.session_key # if it exists, delete it; if not, create it. try: love = Love.objects.get(**filters) love.delete() except Love.DoesNotExist: love = Love(**filters) love.save() # if a next url is set, redirect there if next: return HttpResponseRedirect(next) # if not, redirect to the original object's permalink if target.get_absolute_url is not None: return HttpResponseRedirect(target.get_absolute_url()) # faling both of those, return a 404 raise Http404( 'next not passed to view and get_absolute_url not defined on object')
def toggle_love(request, next=None): """ Toggle love. """ data = request.POST.copy() next = data.get("next", next) content_type = data.get("content_type") object_pk = data.get("object_pk") if content_type == None or object_pk == None: return Http404("No object specified.") try: model = models.get_model(*content_type.split(".", 1)) target = model.objects.get(pk=object_pk) except: return Http404("An error occured trying to get the target object.") form = ToggleLoveForm(target, data=data) if form.security_errors(): def escape(s): return s.replace("<", "<").replace(">", ">") return Http404("Form failed security verification:" % escape(str(form.security_errors()))) # first filter on the object itself filters = form.get_filter_kwargs() # either add a user or a session key to our list of filters if request.user.is_authenticated(): filters['user'] = request.user else: filters['session_key'] = request.session.session_key # if it exists, delete it; if not, create it. try: love = Love.objects.get(**filters) love.delete() except Love.DoesNotExist: love = Love(**filters) love.save() # if a next url is set, redirect there if next: return HttpResponseRedirect(next) # if not, redirect to the original object's permalink if target.get_absolute_url is not None: return HttpResponseRedirect(target.get_absolute_url()) # faling both of those, return a 404 raise Http404('next not passed to view and get_absolute_url not defined on object')
def get_love(sender_username=None, recipient_username=None, limit=None): """Get all love from a particular sender or to a particular recipient. :param sender_username: If present, only return love sent from a particular user. :param recipient_username: If present, only return love sent to a particular user. :param limit: If present, only return this many items. """ sender_username = logic.alias.name_for_alias(sender_username) recipient_username = logic.alias.name_for_alias(recipient_username) if not (sender_username or recipient_username): raise TaintedLove( 'Not gonna give you all the love in the world. Sorry.') if sender_username == recipient_username: raise TaintedLove('Who sends love to themselves? Honestly?') love_query = ( Love.query().filter(Love.secret == False) # noqa .order(-Love.timestamp)) if sender_username: sender_key = Employee.get_key_for_username(sender_username) love_query = love_query.filter(Love.sender_key == sender_key) if recipient_username: recipient_key = Employee.get_key_for_username(recipient_username) love_query = love_query.filter(Love.recipient_key == recipient_key) if limit: return love_query.fetch_async(limit) else: return love_query.fetch_async()
def rebuild_love_count(): utc_dt = datetime.datetime.utcnow() - datetime.timedelta( days=7) # rebuild last week and this week week_start, _ = utc_week_limits(utc_dt) set_toggle_state(LOVE_SENDING_ENABLED, False) logging.info('Deleting LoveCount table... {}MB'.format( memory_usage().current())) ndb.delete_multi( LoveCount.query(LoveCount.week_start >= week_start).fetch( keys_only=True)) employee_dict = {employee.key: employee for employee in Employee.query()} logging.info('Rebuilding LoveCount table... {}MB'.format( memory_usage().current())) cursor = None count = 0 while True: loves, cursor, has_more = Love.query( Love.timestamp >= week_start).fetch_page(500, start_cursor=cursor) for l in loves: LoveCount.update(l, employee_dict=employee_dict) count += len(loves) logging.info('Processed {} loves, {}MB'.format( count, memory_usage().current())) if not has_more: break logging.info('Done. {}MB'.format(memory_usage().current())) set_toggle_state(LOVE_SENDING_ENABLED, True)
def create_love( sender_key, recipient_key, message=DEFAULT_LOVE_MESSAGE, secret=False, ): love = Love( sender_key=sender_key, recipient_key=recipient_key, message=message, secret=secret, ) love.put() return love
def _love_query(start_dt, end_dt, include_secret): query = Love.query().order(-Love.timestamp) if type(start_dt) is datetime: query = query.filter(Love.timestamp >= start_dt) if type(end_dt) is datetime: query = query.filter(Love.timestamp <= end_dt) if type(include_secret) is bool and include_secret is False: query = query.filter(Love.secret == False) # noqa return query
def _send_love(recipient_key, message, sender_key, secret): """Send love and do associated bookkeeping.""" new_love = Love( sender_key=sender_key, recipient_key=recipient_key, message=message, secret=(secret is True), ) new_love.put() LoveCount.update(new_love) # Send email asynchronously taskqueue.add(url='/tasks/love/email', params={'id': new_love.key.id()}) if not secret: logic.event.add_event( logic.event.LOVESENT, {'love_id': new_love.key.id()}, )
def rebuild_love_count(): set_toggle_state(LOVE_SENDING_ENABLED, False) logging.info('Rebuilding LoveCount table...') ndb.delete_multi(LoveCount.query().fetch(keys_only=True)) for l in Love.query().iter(batch_size=1000): LoveCount.update(l) logging.info('Done.') set_toggle_state(LOVE_SENDING_ENABLED, True)
def combine_employees(old_username, new_username): set_toggle_state(LOVE_SENDING_ENABLED, False) old_employee_key = Employee.query(Employee.username == old_username).get( keys_only=True) new_employee_key = Employee.query(Employee.username == new_username).get( keys_only=True) if not old_employee_key: raise NoSuchEmployee(old_username) elif not new_employee_key: raise NoSuchEmployee(new_username) # First, we need to update the actual instances of Love sent to/from the old employee logging.info('Reassigning {}\'s love to {}...'.format( old_username, new_username)) love_to_save = [] # Reassign all love sent FROM old_username for sent_love in Love.query(Love.sender_key == old_employee_key).iter(): sent_love.sender_key = new_employee_key love_to_save.append(sent_love) # Reassign all love sent TO old_username for received_love in Love.query( Love.recipient_key == old_employee_key).iter(): received_love.recipient_key = new_employee_key love_to_save.append(received_love) ndb.put_multi(love_to_save) logging.info('Done.') # Second, we need to update the LoveCount table logging.info('Updating LoveCount table...') love_counts_to_delete, love_counts_to_save = [], [] for old_love_count in LoveCount.query(ancestor=old_employee_key).iter(): # Try to find a corresponding row for the new employee new_love_count = LoveCount.query( ancestor=new_employee_key, filters=(LoveCount.week_start == old_love_count.week_start)).get() if new_love_count is None: # If there's no corresponding row for the new user, create one new_love_count = LoveCount( parent=new_employee_key, received_count=old_love_count.received_count, sent_count=old_love_count.sent_count, week_start=old_love_count.week_start) else: # Otherwise, combine the two rows new_love_count.received_count += old_love_count.received_count new_love_count.sent_count += old_love_count.sent_count # You `delete` keys but you `put` entities... Google's APIs are weird love_counts_to_delete.append(old_love_count.key) love_counts_to_save.append(new_love_count) ndb.delete_multi(love_counts_to_delete) ndb.put_multi(love_counts_to_save) logging.info('Done.') # Now we can delete the old employee logging.info('Deleting employee {}...'.format(old_username)) old_employee_key.delete() logging.info('Done.') # ... Which means we need to rebuild the index rebuild_index() set_toggle_state(LOVE_SENDING_ENABLED, True)