def get(self):
    
    if helpers.authorized(self.request.params['UUID'], self.request.params['authToken'], self.request.params['action']):

      currentUserId = int(self.request.params['UUID'])
      users = User.all()
      projects = Project.all()
      tasks = Task.all()
      watches = Watch.all()
      comments = Comment.all()
      
      # If lastRetrievedAt is '', get full list of non-soft-deleted records (invoked at GUI startup - first time it is run or if local storage is not used)
      # else get incremental list of records updated since last refresh
      if len(self.request.params) > 0:
        try:
          lastRetrievedAt = self.request.params['lastRetrievedAt']
        except:
          lastRetrievedAt = ''
        try:
          loadDoneProjectData = self.request.params['loadDoneProjectData']
        except:
          loadDoneProjectData = 'false'
      
      if lastRetrievedAt != '':
        query = 'updatedAt >'
        timestamp = int(lastRetrievedAt)
        users.filter(query, timestamp)
        users = users.fetch(helpers.MAX_RESULTS)
        projects.filter(query, timestamp)
        projects = projects.fetch(helpers.MAX_RESULTS)
        tasks.filter(query, timestamp)
        tasks = tasks.fetch(helpers.MAX_RESULTS)
        watches.filter(query, timestamp)
        watches = watches.fetch(helpers.MAX_RESULTS)
        comments.filter(query, timestamp)
        comments = comments.fetch(helpers.MAX_RESULTS)
        
      notDoneProjects = []
      doneProjectIds = []
      tasksInNotDoneProjects = []
      tasksInDoneProjectIds = []
      watchesOnTasksInNotDoneProjects = []
      commentsOnTasksInNotDoneProjects = []
      if loadDoneProjectData == 'false':
        for project in projects:
          if project.developmentStatus == '_Done':
            doneProjectIds.append(project.key().id_or_name());
          else:
            notDoneProjects.append(project);
        for task in tasks:
          try:
            idx = doneProjectIds.index(task.projectId)
          except:
            idx = -1
          if idx == -1:
            tasksInNotDoneProjects.append(task);
          else:
            tasksInDoneProjectIds.append(task.key().id_or_name());
        for watch in watches:
          try:
            idx = tasksInDoneProjectIds.index(watch.taskId)
          except:
            idx = -1
          if idx == -1:
            watchesOnTasksInNotDoneProjects.append(watch);

        for comment in comments:
          try:
            idx = tasksInDoneProjectIds.index(comment.taskId)
          except:
            idx = -1
          if idx == -1:
            commentsOnTasksInNotDoneProjects.append(comment);
        
      users_json = helpers.build_user_list_json(helpers.extract_non_deleted_records(users), currentUserId)
      projects_json = helpers.build_project_list_json(helpers.extract_non_deleted_records(projects if loadDoneProjectData == 'true' else notDoneProjects))
      tasks_json = helpers.build_task_list_json(helpers.extract_non_deleted_records(tasks if loadDoneProjectData == 'true' else tasksInNotDoneProjects))
      watches_json = helpers.build_watch_list_json(helpers.extract_non_deleted_records(watches if loadDoneProjectData == 'true' else watchesOnTasksInNotDoneProjects))
      comments_json = helpers.build_comment_list_json(helpers.extract_non_deleted_records(comments if loadDoneProjectData == 'true' else commentsOnTasksInNotDoneProjects))
    
      records_json = {
        "result": {
         "users": users_json,
         "projects": projects_json,
         "tasks": tasks_json,
         "watches": watches_json,
         "comments": comments_json
        }
      }
    
      # Set the response content type and dump the json
      self.response.headers['Content-Type'] = 'application/json'
      self.response.out.write(simplejson.dumps(records_json))
    else:
      helpers.report_unauthorized_access(self.response)
  def get(self):

    if helpers.authorized(self.request.params['UUID'], self.request.params['authToken'], "cleanup"):
      
      now = int(time.time()*1000)
      
      # Delete soft-deleted records older than timestamp (if specified) or older than a month
      try:
        cutoff = self.request.params['cutoff']
        cutoff = int(cutoff)
      except:
        # default to a cutoff time a month ago
        cutoff = now - helpers.MONTH_MILLISECONDS
    
      users_json = helpers.build_user_list_json(helpers.purge_soft_deleted_records(User.all(), cutoff), None)
      projects_json = helpers.build_project_list_json(helpers.purge_soft_deleted_records(Project.all(), cutoff))
      tasks_json = helpers.build_task_list_json(helpers.purge_soft_deleted_records(Task.all(), cutoff))
      watches_json = helpers.build_watch_list_json(helpers.purge_soft_deleted_records(Watch.all(), cutoff))
      comments_json = helpers.build_comment_list_json(helpers.purge_soft_deleted_records(Comment.all(), cutoff))
    
      # Handle IDs referencing non-existent records:
      # * non-existent task projectId/submitterId/assigneeId should be set to null
      # * watches with non-existent taskId/watchId should be soft-deleted
      # * set updatedAt for all records being modified
      user_ids = helpers.extract_record_ids(User.all())
      project_ids = helpers.extract_record_ids(Project.all())
      tasks = Task.all()
      task_ids = helpers.extract_record_ids(tasks)
      tasks_updated = []
      for task in tasks:
        updated = False
        project_id = task.projectId
        if project_id != None and project_id != '':
          try:
            idx = project_ids.index(project_id)
          except:
            idx = -1
          if idx == -1:
            task.projectId = None
            updated = True
        submitter_id = task.submitterId
        if submitter_id != None and submitter_id != '':
          try:
            idx = user_ids.index(submitter_id)
          except:
            idx = -1
          if idx == -1:
            task.submitterId = None
            updated = True
        assignee_id = task.assigneeId
        if assignee_id != None and assignee_id != '':
          try:
            idx = user_ids.index(assignee_id)
          except:
            idx = -1
          if idx == -1:
            task.assigneeId = None
            updated = True
        if updated:
          task.updatedAt = now
          task.put()
          tasks_updated.append(task)
      tasks_updated_json = helpers.build_task_list_json(tasks_updated)
          
      watches = Watch.all()
      watches_soft_deleted = []
      for watch in watches:
        if watch.status != 'deleted':
          task_id = watch.taskId
          if task_id != None and task_id != '':
            try:
              task_idx = task_ids.index(task_id)
            except:
              task_idx = -1
          user_id = watch.userId
          if user_id != None and user_id != '':
            try:
              user_idx = user_ids.index(user_id)
            except:
              user_idx = -1
          if task_idx == -1 or user_idx == -1:
            watch.status = 'deleted'
            watch.updatedAt = now
            watch.put()
            watches_soft_deleted.append(watch)
      watches_soft_deleted_json = helpers.build_watch_list_json(watches_soft_deleted)
          
      comments = Comment.all()
      comments_soft_deleted = []
      for comment in comments:
        if comment.status != 'deleted':
          task_id = comment.taskId
          if task_id != None and task_id != '':
            try:
              task_idx = task_ids.index(task_id)
            except:
              task_idx = -1
          user_id = comment.userId
          if user_id != None and user_id != '':
            try:
              user_idx = user_ids.index(user_id)
            except:
              user_idx = -1
          if task_idx == -1 or user_idx == -1:
            comment.status = 'deleted'
            comment.updatedAt = now
            comment.put()
            comments_soft_deleted.append(comment)
      comments_soft_deleted_json = helpers.build_comment_list_json(comments_soft_deleted)
          
      # Return all affected records broken down by category
      result = {
       "cutoff": cutoff,
       "usersDeleted": users_json,
       "projectsDeleted": projects_json,
       "tasksDeleted": tasks_json,
       "watchesDeleted": watches_json,
       "comentsDeleted": comments_json,
       "tasksUpdated": tasks_updated_json,
       "watchesSoftDeleted": watches_soft_deleted_json,
       "commentsSoftDeleted": comments_soft_deleted_json
      }
      records_json = {
        "result": result
      }
  
      self.response.set_status(200, "Cleanup done")
      self.response.headers['Content-Type'] = 'application/json'
      self.response.out.write(simplejson.dumps(records_json))
    
    else:
      helpers.report_unauthorized_access(self.response)