Example #1
0
  def testQueryForUser(self):
    """Tests that queryForUser returns a query for all GCIMessage entities from
    a particular user.
    """

    expected_keys = set(self.user_1_msg_keys)
    actual_keys = set(gcimessage_logic.queryForUser(
        user=self.user_keys[0]).fetch(20, keys_only=True))
    self.assertEqual(expected_keys, actual_keys)

    expected_keys = set(self.user_2_msg_keys)
    actual_keys = set(gcimessage_logic.queryForUser(
        user=self.user_keys[1]).fetch(20, keys_only=True))
    self.assertEqual(expected_keys, actual_keys)
Example #2
0
    def testQueryForUser(self):
        """Tests that queryForUser returns a query for all GCIMessage entities from
    a particular user.
    """

        expected_keys = set(self.user_1_msg_keys)
        actual_keys = set(
            gcimessage_logic.queryForUser(user=self.user_keys[0]).fetch(
                20, keys_only=True))
        self.assertEqual(expected_keys, actual_keys)

        expected_keys = set(self.user_2_msg_keys)
        actual_keys = set(
            gcimessage_logic.queryForUser(user=self.user_keys[1]).fetch(
                20, keys_only=True))
        self.assertEqual(expected_keys, actual_keys)
Example #3
0
def confirm_delete(profile):
  """Deletes the given profile entity and also the user entity if possible.

  1. Deletes the profile.
  2. Deletes the user entity if no other profiles exist for the user.
  3. Removes the user from task notification subscription lists.
  4. Replaces GCITask created_by, modified_by, student and GCIComment
     created_by properties with dummy "melange_deleted_user" profile or user
     entity.
  5. Replaces GCIMessage author with dummy "melange_deleted_user".
  6. Replaces GCIConversation creator with dummy "melange_deleted_user".
  7. Removes GCIConversationUser entities representing the user's involvement
     in a GCIConversation.

  This method implements a giant XG transaction, but should not take a long
  time because experience has shown that there won't be too much data to
  modify or delete.

  Args:
    profile: GCIProfile entity of the user.
  """
  profile_key = profile.key()

  program_ndb_key = ndb.Key.from_old_key(profile.program.key())
  user_ndb_key = ndb.Key.from_old_key(profile.parent_key())

  # Cannot delete the user entity if the user has other profiles, so set it
  # to False in that case.
  user_delete = not (profile_logic.hasOtherGCIProfiles(profile) or
                     profile_logic.hasOtherGCIProfiles(profile))

  task_sub_q = task_model.GCITask.all().filter('subscribers', profile)
  task_sub_remove_list = []
  for task in task_sub_q.run():
    task_sub_remove_list.append(task)

  tasks_created_by_q = task_model.GCITask.all().filter('created_by', profile)
  task_created_list = []
  for task in tasks_created_by_q.run():
    task_created_list.append(task)

  tasks_modified_by_q = task_model.GCITask.all().filter('modified_by', profile)
  task_modified_list = []
  for task in tasks_modified_by_q.run():
    task_modified_list.append(task)

  tasks_student_q = task_model.GCITask.all().filter('student', profile)
  task_student_list = []
  for task in tasks_student_q.run():
    task_student_list.append(task)

  comments_created_by_q = comment_model.GCIComment.all().filter(
      'created_by', profile.user)
  comments_created_by_list = []
  for comment in comments_created_by_q.run():
    comments_created_by_list.append(comment)

  conversations = conversation_logic.queryForProgramAndCreator(
      program_ndb_key, user_ndb_key)

  messages = message_logic.queryForUser(user_ndb_key)

  conversation_users = conversation_logic.queryForProgramAndUser(
      program_ndb_key, user_ndb_key)

  dummy_user = user_logic.getOrCreateDummyMelangeDeletedUser()
  dummy_profile = profile_logic.getOrCreateDummyMelangeDeletedProfile(
      profile.program)

  dummy_user_ndb_key = ndb.Key.from_old_key(dummy_user.key())

  options = db.create_transaction_options(xg=True)

  def delete_account_txn():
    entities_to_save = set([])
    entities_to_del = set([])

    # The batch size for query.run() is 20, in most of the cases we have
    # seen so far the user had a few tasks with subscriptions, created_by,
    # modified_by etc., so this should still be single datastore hits per
    # loop. Also, by running the query outside the transaction we may run
    # into situations of user subscribing to the task or creating or modifying
    # tasks or performing another activity after this batch fetch. However,
    # the chances of that happening is very low and can be traded-off for
    # the bigger problem of half run transactions.

    for conversation in conversations:
      conversation.creator = dummy_user_ndb_key
      conversation.put()

    for message in messages:
      message.author = dummy_user_ndb_key
      message.put()

    for conversation_user in conversation_users:
      conversation_user.key.delete()

    for task in task_sub_remove_list:
      task.subscribers.remove(profile_key)
      entities_to_save.add(task)

    for task in task_created_list:
      task.created_by = dummy_profile
      entities_to_save.add(task)

    for task in task_modified_list:
      task.modified_by = dummy_profile
      entities_to_save.add(task)

    for task in task_student_list:
      task.student = dummy_profile
      entities_to_save.add(task)

    for comment in comments_created_by_list:
      comment.created_by = dummy_user
      entities_to_save.add(comment)

    if profile.student_info:
      entities_to_del.add(profile.student_info)
      entities_to_del.add(profile)

    if user_delete:
      entities_to_del.add(profile.parent())

    db.put(entities_to_save)
    db.delete(entities_to_del)

  db.run_in_transaction_options(options, delete_account_txn)
Example #4
0
def confirm_delete(profile):
    """Deletes the given profile entity and also the user entity if possible.

  1. Deletes the profile.
  2. Deletes the user entity if no other profiles exist for the user.
  3. Removes the user from task notification subscription lists.
  4. Replaces GCITask created_by, modified_by, student and GCIComment
     created_by properties with dummy "melange_deleted_user" profile or user
     entity.
  5. Replaces GCIMessage author with dummy "melange_deleted_user".
  6. Replaces GCIConversation creator with dummy "melange_deleted_user".
  7. Removes GCIConversationUser entities representing the user's involvement
     in a GCIConversation.

  This method implements a giant XG transaction, but should not take a long
  time because experience has shown that there won't be too much data to
  modify or delete.

  Args:
    profile: GCIProfile entity of the user.
  """
    profile_key = profile.key()

    program_ndb_key = ndb.Key.from_old_key(profile.program.key())
    user_ndb_key = ndb.Key.from_old_key(profile.parent_key())

    # Cannot delete the user entity if the user has other profiles, so set it
    # to False in that case.
    user_delete = not (profile_logic.hasOtherGCIProfiles(profile)
                       or profile_logic.hasOtherGCIProfiles(profile))

    task_sub_q = task_model.GCITask.all().filter('subscribers', profile)
    task_sub_remove_list = []
    for task in task_sub_q.run():
        task_sub_remove_list.append(task)

    tasks_created_by_q = task_model.GCITask.all().filter('created_by', profile)
    task_created_list = []
    for task in tasks_created_by_q.run():
        task_created_list.append(task)

    tasks_modified_by_q = task_model.GCITask.all().filter(
        'modified_by', profile)
    task_modified_list = []
    for task in tasks_modified_by_q.run():
        task_modified_list.append(task)

    tasks_student_q = task_model.GCITask.all().filter('student', profile)
    task_student_list = []
    for task in tasks_student_q.run():
        task_student_list.append(task)

    comments_created_by_q = comment_model.GCIComment.all().filter(
        'created_by', profile.user)
    comments_created_by_list = []
    for comment in comments_created_by_q.run():
        comments_created_by_list.append(comment)

    conversations = conversation_logic.queryForProgramAndCreator(
        program_ndb_key, user_ndb_key)

    messages = message_logic.queryForUser(user_ndb_key)

    conversation_users = conversation_logic.queryForProgramAndUser(
        program_ndb_key, user_ndb_key)

    dummy_user = user_logic.getOrCreateDummyMelangeDeletedUser()
    dummy_profile = profile_logic.getOrCreateDummyMelangeDeletedProfile(
        profile.program)

    dummy_user_ndb_key = ndb.Key.from_old_key(dummy_user.key())

    options = db.create_transaction_options(xg=True)

    def delete_account_txn():
        entities_to_save = set([])
        entities_to_del = set([])

        # The batch size for query.run() is 20, in most of the cases we have
        # seen so far the user had a few tasks with subscriptions, created_by,
        # modified_by etc., so this should still be single datastore hits per
        # loop. Also, by running the query outside the transaction we may run
        # into situations of user subscribing to the task or creating or modifying
        # tasks or performing another activity after this batch fetch. However,
        # the chances of that happening is very low and can be traded-off for
        # the bigger problem of half run transactions.

        for conversation in conversations:
            conversation.creator = dummy_user_ndb_key
            conversation.put()

        for message in messages:
            message.author = dummy_user_ndb_key
            message.put()

        for conversation_user in conversation_users:
            conversation_user.key.delete()

        for task in task_sub_remove_list:
            task.subscribers.remove(profile_key)
            entities_to_save.add(task)

        for task in task_created_list:
            task.created_by = dummy_profile
            entities_to_save.add(task)

        for task in task_modified_list:
            task.modified_by = dummy_profile
            entities_to_save.add(task)

        for task in task_student_list:
            task.student = dummy_profile
            entities_to_save.add(task)

        for comment in comments_created_by_list:
            comment.created_by = dummy_user
            entities_to_save.add(comment)

        if profile.student_info:
            entities_to_del.add(profile.student_info)
            entities_to_del.add(profile)

        if user_delete:
            entities_to_del.add(profile.parent())

        db.put(entities_to_save)
        db.delete(entities_to_del)

    db.run_in_transaction_options(options, delete_account_txn)