Merge branch 'main' into avm99963-monorail

Merged commit 34d8229ae2b51fb1a15bd208e6fe6185c94f6266

GitOrigin-RevId: 7ee0917f93a577e475f8e09526dd144d245593f4
diff --git a/sitewide/custom_404.py b/sitewide/custom_404.py
index 557d1ff..62b9c1f 100644
--- a/sitewide/custom_404.py
+++ b/sitewide/custom_404.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Page class for generating somewhat informative project-page 404s.
 
@@ -17,7 +16,6 @@
 
 from six.moves import http_client
 from framework import exceptions
-from framework import flaskservlet
 from framework import servlet
 
 
@@ -41,5 +39,5 @@
         'http_response_code': http_client.NOT_FOUND,
     }
 
-  # def Get404Page(self, **kwargs):
-  #   return self.handler(**kwargs)
+  def Get404Page(self, **kwargs):
+    return self.handler(**kwargs)
diff --git a/sitewide/group_helpers.py b/sitewide/group_helpers.py
index b0195c5..4f2b3b3 100644
--- a/sitewide/group_helpers.py
+++ b/sitewide/group_helpers.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Helper functions used in user group modules."""
 from __future__ import print_function
@@ -9,7 +8,7 @@
 from __future__ import absolute_import
 
 from framework import framework_views
-from proto import usergroup_pb2
+from mrproto import usergroup_pb2
 
 
 class GroupVisibilityView(object):
diff --git a/sitewide/groupadmin.py b/sitewide/groupadmin.py
index 09593e0..1fdfcfe 100644
--- a/sitewide/groupadmin.py
+++ b/sitewide/groupadmin.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """A class to display user group admin page."""
 from __future__ import print_function
@@ -13,17 +12,16 @@
 
 import ezt
 
-from framework import flaskservlet
 from framework import framework_helpers
 from framework import permissions
 from framework import servlet
 from framework import urls
-from proto import usergroup_pb2
+from mrproto import usergroup_pb2
 from services import usergroup_svc
 from sitewide import group_helpers
 
 
-class GroupAdmin(flaskservlet.FlaskServlet):
+class GroupAdmin(servlet.Servlet):
   """The group admin page."""
 
   _PAGE_TEMPLATE = 'sitewide/group-admin-page.ezt'
diff --git a/sitewide/groupcreate.py b/sitewide/groupcreate.py
index 2c0ece7..9ac2d15 100644
--- a/sitewide/groupcreate.py
+++ b/sitewide/groupcreate.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """A page for site admins to create a new user group."""
 from __future__ import print_function
@@ -11,14 +10,15 @@
 import logging
 import re
 
-from framework import exceptions, flaskservlet
+from framework import exceptions
 from framework import framework_helpers
 from framework import permissions
-from proto import usergroup_pb2
+from framework import servlet
+from mrproto import usergroup_pb2
 from sitewide import group_helpers
 
 
-class GroupCreate(flaskservlet.FlaskServlet):
+class GroupCreate(servlet.Servlet):
   """Shows a page with a simple form to create a user group."""
 
   _PAGE_TEMPLATE = 'sitewide/group-create-page.ezt'
diff --git a/sitewide/groupdetail.py b/sitewide/groupdetail.py
index 1f16a0a..7dfa983 100644
--- a/sitewide/groupdetail.py
+++ b/sitewide/groupdetail.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """A class to display a user group, including a paginated list of members."""
 from __future__ import print_function
@@ -14,21 +13,20 @@
 import ezt
 
 from framework import exceptions
-from framework import flaskservlet
 from framework import framework_helpers
 from framework import framework_views
 from framework import paginate
 from framework import permissions
 from framework import servlet
 from project import project_helpers
-from proto import usergroup_pb2
+from mrproto import usergroup_pb2
 from sitewide import group_helpers
 from sitewide import sitewide_views
 
 MEMBERS_PER_PAGE = 50
 
 
-class GroupDetail(flaskservlet.FlaskServlet):
+class GroupDetail(servlet.Servlet):
   """The group detail page presents information about one user group."""
 
   _PAGE_TEMPLATE = 'sitewide/group-detail-page.ezt'
diff --git a/sitewide/grouplist.py b/sitewide/grouplist.py
index 627ca22..4fe4641 100644
--- a/sitewide/grouplist.py
+++ b/sitewide/grouplist.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Classes to list user groups."""
 from __future__ import print_function
@@ -13,7 +12,7 @@
 
 import ezt
 
-from framework import flaskservlet, framework_helpers
+from framework import framework_helpers
 from framework import permissions
 from framework import servlet
 from framework import urls
@@ -37,71 +36,6 @@
   def GatherPageData(self, mr):
     """Build up a dictionary of data values to use when rendering the page."""
     group_views = [
-        sitewide_views.GroupView(*groupinfo) for groupinfo in
-        self.services.usergroup.GetAllUserGroupsInfo(mr.cnxn)]
-    group_views.sort(key=lambda gv: gv.name)
-    offer_group_deletion = mr.perms.CanUsePerm(
-        permissions.DELETE_GROUP, mr.auth.effective_ids, None, [])
-    offer_group_creation = mr.perms.CanUsePerm(
-        permissions.CREATE_GROUP, mr.auth.effective_ids, None, [])
-
-    return {
-        'form_token': xsrf.GenerateToken(
-            mr.auth.user_id, '%s.do' % urls.GROUP_DELETE),
-        'groups': group_views,
-        'offer_group_deletion': ezt.boolean(offer_group_deletion),
-        'offer_group_creation': ezt.boolean(offer_group_creation),
-        }
-
-  def ProcessFormData(self, mr, post_data):
-    """Process the posted form."""
-    if 'removebtn' in post_data:
-      return self.ProcessDeleteGroups(mr, post_data)
-
-  def ProcessDeleteGroups(self, mr, post_data):
-    """Process request to delete groups."""
-    if not mr.perms.CanUsePerm(
-        permissions.DELETE_GROUP, mr.auth.effective_ids, None, []):
-      raise permissions.PermissionException(
-          'User is not permitted to delete groups')
-
-    remove_groups = [int(g) for g in post_data.getall('remove')]
-    # TODO(crbug.com/monorail/10936): getall in Flask is getlist
-    # remove_groups = [int(g) for g in post_data.getlist('remove')]
-
-    if not mr.errors.AnyErrors():
-      self.services.usergroup.DeleteGroups(mr.cnxn, remove_groups)
-
-    if mr.errors.AnyErrors():
-      self.PleaseCorrect(mr)
-    else:
-      return framework_helpers.FormatAbsoluteURL(
-          mr, '/g', include_project=False,
-          saved=1, ts=int(time.time()))
-
-  # def GetGroupList(self, **kwargs):
-  #   return self.handler(**kwargs)
-
-  # def PostGroupList(self, **kwargs):
-  #   return self.handler(**kwargs)
-
-
-class FlaskGroupList(flaskservlet.FlaskServlet):
-  """Shows a page with a simple form to create a user group."""
-
-  _PAGE_TEMPLATE = 'sitewide/group-list-page.ezt'
-
-  def AssertBasePermission(self, mr):
-    """Assert that the user has the permissions needed to view this page."""
-    super(FlaskGroupList, self).AssertBasePermission(mr)
-
-    if not mr.perms.HasPerm(permissions.VIEW_GROUP, None, None):
-      raise permissions.PermissionException(
-          'User is not allowed to view list of user groups')
-
-  def GatherPageData(self, mr):
-    """Build up a dictionary of data values to use when rendering the page."""
-    group_views = [
         sitewide_views.GroupView(*groupinfo)
         for groupinfo in self.services.usergroup.GetAllUserGroupsInfo(mr.cnxn)
     ]
diff --git a/sitewide/hostinghome.py b/sitewide/hostinghome.py
index b744935..7ee92d2 100644
--- a/sitewide/hostinghome.py
+++ b/sitewide/hostinghome.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """A class to display the hosting home page."""
 from __future__ import print_function
@@ -14,14 +13,14 @@
 import settings
 from businesslogic import work_env
 from framework import exceptions
-from framework import flaskservlet
 from framework import permissions
+from framework import servlet
 from framework import urls
 from project import project_views
 from sitewide import projectsearch
 
 
-class HostingHome(flaskservlet.FlaskServlet):
+class HostingHome(servlet.Servlet):
   """HostingHome shows the project list and link to create a project."""
 
   _PAGE_TEMPLATE = 'sitewide/hosting-home-page.ezt'
diff --git a/sitewide/moved.py b/sitewide/moved.py
index 8c2935f..0be5c37 100644
--- a/sitewide/moved.py
+++ b/sitewide/moved.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """A class to display a message explaining that a project has moved.
 
@@ -13,14 +12,14 @@
 
 import logging
 
-from framework import exceptions, flaskservlet
+from framework import exceptions
 from framework import framework_helpers
 from framework import servlet
 from framework import urls
 from project import project_constants
 
 
-class ProjectMoved(flaskservlet.FlaskServlet):
+class ProjectMoved(servlet.Servlet):
   """The ProjectMoved page explains that the project has moved."""
 
   _PAGE_TEMPLATE = 'sitewide/moved-page.ezt'
diff --git a/sitewide/projectcreate.py b/sitewide/projectcreate.py
index 37d02c8..f6c3842 100644
--- a/sitewide/projectcreate.py
+++ b/sitewide/projectcreate.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Classes for users to create a new project."""
 from __future__ import print_function
@@ -15,7 +14,7 @@
 
 import settings
 from businesslogic import work_env
-from framework import exceptions, flaskservlet
+from framework import exceptions
 from framework import filecontent
 from framework import framework_helpers
 from framework import gcs_helpers
@@ -37,7 +36,7 @@
 _MSG_MISSING_PROJECT_SUMMARY = 'Missing project summary'
 
 
-class ProjectCreate(flaskservlet.FlaskServlet):
+class ProjectCreate(servlet.Servlet):
   """Shows a page with a simple form to create a project."""
 
   _PAGE_TEMPLATE = 'sitewide/project-create-page.ezt'
@@ -115,8 +114,8 @@
       try:
         gcs_helpers.CheckMimeTypeResizable(
             filecontent.GuessContentTypeFromFilename(item.filename))
-      except gcs_helpers.UnsupportedMimeType, e:
-        mr.errors.logo = e.message
+      except gcs_helpers.UnsupportedMimeType as e:
+        mr.errors.logo = str(e)
 
     # 2. Call services layer to save changes.
     if not mr.errors.AnyErrors():
@@ -137,7 +136,7 @@
             item = post_data['logo']
             logo_file_name = item.filename
             logo_gcs_id = gcs_helpers.StoreLogoInGCS(
-                logo_file_name, item.value, project_id)
+                logo_file_name, item.read(), project_id)
             we.UpdateProject(
                 project_id, logo_gcs_id=logo_gcs_id,
                 logo_file_name=logo_file_name)
diff --git a/sitewide/projectsearch.py b/sitewide/projectsearch.py
index 8ef5fee..acbcdb9 100644
--- a/sitewide/projectsearch.py
+++ b/sitewide/projectsearch.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Helper functions and classes used when searching for projects."""
 from __future__ import print_function
diff --git a/sitewide/sitewide_helpers.py b/sitewide/sitewide_helpers.py
index 33f53c3..b449002 100644
--- a/sitewide/sitewide_helpers.py
+++ b/sitewide/sitewide_helpers.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Helper functions used in sitewide servlets."""
 from __future__ import print_function
@@ -11,7 +10,7 @@
 import logging
 
 from framework import permissions
-from proto import project_pb2
+from mrproto import project_pb2
 
 
 def GetViewableStarredProjects(
diff --git a/sitewide/sitewide_views.py b/sitewide/sitewide_views.py
index 64b33bd..d8dddd6 100644
--- a/sitewide/sitewide_views.py
+++ b/sitewide/sitewide_views.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """View objects to help display users and groups in UI templates."""
 from __future__ import print_function
diff --git a/sitewide/test/custom_404_test.py b/sitewide/test/custom_404_test.py
index b47501d..fe099d6 100644
--- a/sitewide/test/custom_404_test.py
+++ b/sitewide/test/custom_404_test.py
@@ -1,7 +1,6 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2017 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unit tests for the custom_404 servlet."""
 from __future__ import print_function
@@ -23,7 +22,7 @@
   def setUp(self):
     self.services = service_manager.Services(
         project=fake.ProjectService())
-    self.servlet = custom_404.ErrorPage('req', 'res', services=self.services)
+    self.servlet = custom_404.ErrorPage(services=self.services)
 
   def testGatherPageData_NoProjectSpecified(self):
     """Project was not included in URL, so raise exception, will cause 400."""
diff --git a/sitewide/test/group_helpers_test.py b/sitewide/test/group_helpers_test.py
index af03d08..02ecfbd 100644
--- a/sitewide/test/group_helpers_test.py
+++ b/sitewide/test/group_helpers_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unit test for User Group helpers."""
 from __future__ import print_function
@@ -10,8 +9,8 @@
 
 import unittest
 
-from proto import user_pb2
-from proto import usergroup_pb2
+from mrproto import user_pb2
+from mrproto import usergroup_pb2
 from sitewide import group_helpers
 
 
diff --git a/sitewide/test/groupadmin_test.py b/sitewide/test/groupadmin_test.py
index 72dfa9d..1322a0f 100644
--- a/sitewide/test/groupadmin_test.py
+++ b/sitewide/test/groupadmin_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unit test for User Group admin servlet."""
 from __future__ import print_function
@@ -11,7 +10,7 @@
 import unittest
 
 from framework import permissions
-from proto import usergroup_pb2
+from mrproto import usergroup_pb2
 from services import service_manager
 from sitewide import groupadmin
 from testing import fake
diff --git a/sitewide/test/groupcreate_test.py b/sitewide/test/groupcreate_test.py
index f82fb74..2944d11 100644
--- a/sitewide/test/groupcreate_test.py
+++ b/sitewide/test/groupcreate_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unit test for User Group creation servlet."""
 from __future__ import print_function
@@ -12,8 +11,8 @@
 
 import settings
 from framework import permissions
-from proto import site_pb2
-from proto import usergroup_pb2
+from mrproto import site_pb2
+from mrproto import usergroup_pb2
 from services import service_manager
 from sitewide import groupcreate
 from testing import fake
diff --git a/sitewide/test/groupdetail_test.py b/sitewide/test/groupdetail_test.py
index f294606..dc341ee 100644
--- a/sitewide/test/groupdetail_test.py
+++ b/sitewide/test/groupdetail_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unit test for User Group Detail servlet."""
 from __future__ import print_function
diff --git a/sitewide/test/grouplist_test.py b/sitewide/test/grouplist_test.py
index 9ec6bd5..9f838a5 100644
--- a/sitewide/test/grouplist_test.py
+++ b/sitewide/test/grouplist_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unit test for User Group List servlet."""
 from __future__ import print_function
@@ -25,7 +24,7 @@
   def setUp(self):
     self.services = service_manager.Services(
         usergroup=fake.UserGroupService())
-    self.servlet = grouplist.GroupList('req', 'res', services=self.services)
+    self.servlet = grouplist.GroupList(services=self.services)
     self.mr = testing_helpers.MakeMonorailRequest()
     self.testbed = testbed.Testbed()
     self.testbed.activate()
diff --git a/sitewide/test/hostinghome_test.py b/sitewide/test/hostinghome_test.py
index de125a5..8a486f8 100644
--- a/sitewide/test/hostinghome_test.py
+++ b/sitewide/test/hostinghome_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Tests for the Monorail home page."""
 from __future__ import print_function
@@ -15,8 +14,8 @@
 
 import settings
 from framework import permissions
-from proto import project_pb2
-from proto import site_pb2
+from mrproto import project_pb2
+from mrproto import site_pb2
 from services import service_manager
 from sitewide import hostinghome
 from sitewide import projectsearch
diff --git a/sitewide/test/moved_test.py b/sitewide/test/moved_test.py
index eccb195..2f4ee4f 100644
--- a/sitewide/test/moved_test.py
+++ b/sitewide/test/moved_test.py
@@ -1,17 +1,15 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unit tests for the moved project notification page servlet."""
 from __future__ import print_function
 from __future__ import division
 from __future__ import absolute_import
 
+import six
 import unittest
 
-import webapp2
-
 from framework import exceptions
 from services import service_manager
 from sitewide import moved
@@ -62,9 +60,8 @@
         path='/hosting/moved?project=%s' % self.old_project)
 
     page_data = self.servlet.GatherPageData(mr)
-    self.assertItemsEqual(
-        ['project_name', 'moved_to_url'],
-        list(page_data.keys()))
+    six.assertCountEqual(
+        self, ['project_name', 'moved_to_url'], list(page_data.keys()))
     self.assertEqual(self.old_project, page_data['project_name'])
     self.assertEqual('https://other-tracker.bugs', page_data['moved_to_url'])
 
@@ -76,9 +73,8 @@
         path='/hosting/moved?project=%s' % self.old_project)
 
     page_data = self.servlet.GatherPageData(mr)
-    self.assertItemsEqual(
-        ['project_name', 'moved_to_url'],
-        list(page_data.keys()))
+    six.assertCountEqual(
+        self, ['project_name', 'moved_to_url'], list(page_data.keys()))
     self.assertEqual(self.old_project, page_data['project_name'])
     self.assertEqual('http://127.0.0.1/p/new-project/',
                      page_data['moved_to_url'])
@@ -91,9 +87,8 @@
         path='/hosting/moved?project=%s' % self.old_project)
 
     page_data = self.servlet.GatherPageData(mr)
-    self.assertItemsEqual(
-        ['project_name', 'moved_to_url'],
-        list(page_data.keys()))
+    six.assertCountEqual(
+        self, ['project_name', 'moved_to_url'], list(page_data.keys()))
     self.assertEqual(self.old_project, page_data['project_name'])
     self.assertEqual('http://127.0.0.1/p/http-project/',
                      page_data['moved_to_url'])
@@ -106,8 +101,7 @@
         path='/hosting/moved?project=%s' % self.old_project)
 
     page_data = self.servlet.GatherPageData(mr)
-    self.assertItemsEqual(
-        ['project_name', 'moved_to_url'],
-        list(page_data.keys()))
+    six.assertCountEqual(
+        self, ['project_name', 'moved_to_url'], list(page_data.keys()))
     self.assertEqual(self.old_project, page_data['project_name'])
     self.assertEqual('#invalid-destination-url', page_data['moved_to_url'])
diff --git a/sitewide/test/projectcreate_test.py b/sitewide/test/projectcreate_test.py
index 13dc97b..a79b9df 100644
--- a/sitewide/test/projectcreate_test.py
+++ b/sitewide/test/projectcreate_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unittests for the Project Creation servlet."""
 from __future__ import print_function
@@ -12,8 +11,8 @@
 
 import settings
 from framework import permissions
-from proto import project_pb2
-from proto import site_pb2
+from mrproto import project_pb2
+from mrproto import site_pb2
 from services import service_manager
 from sitewide import projectcreate
 from testing import fake
diff --git a/sitewide/test/projectsearch_test.py b/sitewide/test/projectsearch_test.py
index a0d941d..cd63e7f 100644
--- a/sitewide/test/projectsearch_test.py
+++ b/sitewide/test/projectsearch_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unittests for the projectsearch module."""
 from __future__ import print_function
@@ -12,7 +11,7 @@
 import unittest
 
 from framework import profiler
-from proto import project_pb2
+from mrproto import project_pb2
 from services import service_manager
 from sitewide import projectsearch
 from testing import fake
@@ -24,14 +23,14 @@
   def setUp(self):
     self.services = service_manager.Services(
         project=fake.ProjectService())
-    self.services.project.GetVisibleLiveProjects = mock.MagicMock()
+    self.services.project.GetVisibleProjects = mock.MagicMock()
 
     for idx, letter in enumerate('abcdefghijklmnopqrstuvwxyz'):
       self.services.project.TestAddProject(letter, project_id=idx + 1)
     for idx in range(27, 110):
       self.services.project.TestAddProject(str(idx), project_id=idx)
 
-    self.addCleanup(mock.patch.stopall())
+    self.addCleanup(mock.patch.stopall)
 
   def TestPipeline(self, expected_last, expected_len):
     mr = testing_helpers.MakeMonorailRequest()
@@ -47,29 +46,28 @@
     return pipeline
 
   def testZeroResults(self):
-    self.services.project.GetVisibleLiveProjects.return_value = []
+    self.services.project.GetVisibleProjects.return_value = []
 
     pipeline = self.TestPipeline(0, 0)
 
-    self.services.project.GetVisibleLiveProjects.assert_called_once()
+    self.services.project.GetVisibleProjects.assert_called_once()
     self.assertListEqual([], pipeline.visible_results)
 
   def testNonzeroResults(self):
-    self.services.project.GetVisibleLiveProjects.return_value = [1, 2, 3]
+    self.services.project.GetVisibleProjects.return_value = [1, 2, 3]
 
     pipeline = self.TestPipeline(3, 3)
 
-    self.services.project.GetVisibleLiveProjects.assert_called_once()
+    self.services.project.GetVisibleProjects.assert_called_once()
     self.assertListEqual(
         [1, 2, 3], [p.project_id for p in pipeline.visible_results])
 
   def testTwoPageResults(self):
     """Test more than one pagination page of results."""
-    self.services.project.GetVisibleLiveProjects.return_value = list(
-        range(1, 106))
+    self.services.project.GetVisibleProjects.return_value = list(range(1, 106))
 
     pipeline = self.TestPipeline(100, 100)
 
-    self.services.project.GetVisibleLiveProjects.assert_called_once()
+    self.services.project.GetVisibleProjects.assert_called_once()
     self.assertEqual(
         '/hosting/search?num=100&start=100', pipeline.pagination.next_url)
diff --git a/sitewide/test/sitewide_helpers_test.py b/sitewide/test/sitewide_helpers_test.py
index d292b6f..03905d9 100644
--- a/sitewide/test/sitewide_helpers_test.py
+++ b/sitewide/test/sitewide_helpers_test.py
@@ -1,16 +1,16 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unit tests for the sitewide_helpers module."""
 from __future__ import print_function
 from __future__ import division
 from __future__ import absolute_import
 
+import six
 import unittest
 
-from proto import project_pb2
+from mrproto import project_pb2
 from services import service_manager
 from sitewide import sitewide_helpers
 from testing import fake
@@ -93,7 +93,7 @@
     # Check names rather than Project objects so that output is easier to read.
     actual_names = [p.project_name for p in actual_projects]
     expected_names = [p.project_name for p in expected_projects]
-    self.assertItemsEqual(expected_names, actual_names)
+    six.assertCountEqual(self, expected_names, actual_names)
 
   def testFilterViewableProjects_CantViewArchived(self):
     projects = list(sitewide_helpers.FilterViewableProjects(
diff --git a/sitewide/test/sitewide_views_test.py b/sitewide/test/sitewide_views_test.py
index ed2515f..3622bdc 100644
--- a/sitewide/test/sitewide_views_test.py
+++ b/sitewide/test/sitewide_views_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unit tests for sitewide_views module."""
 from __future__ import print_function
@@ -10,7 +9,7 @@
 
 import unittest
 
-from proto import usergroup_pb2
+from mrproto import usergroup_pb2
 from sitewide import sitewide_views
 
 
diff --git a/sitewide/test/userprofile_test.py b/sitewide/test/userprofile_test.py
index b4e29d8..42c901e 100644
--- a/sitewide/test/userprofile_test.py
+++ b/sitewide/test/userprofile_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Tests for the user profile page."""
 from __future__ import print_function
@@ -10,21 +9,18 @@
 
 import mock
 import unittest
-import logging
-import webapp2
 import ezt
+import six
 
-from framework import framework_helpers
+from google.appengine.ext import testbed
+import pytest
+
 from framework import framework_views
 from framework import permissions
-from proto import project_pb2
-from proto import user_pb2
+from mrproto import project_pb2
 from services import service_manager
 from sitewide import userprofile
 from testing import fake
-from testing import testing_helpers
-
-from google.appengine.ext import testbed
 
 REGULAR_USER_ID = 111
 ADMIN_USER_ID = 222
@@ -48,8 +44,7 @@
   mr.viewed_user_auth.effective_ids = {viewed_user_id}
   mr.viewed_user_auth.user_view = framework_views.UserView(viewed_user_pb)
   mr.viewed_user_name = viewed_user_name
-  mr.request = webapp2.Request.blank("/")
-  mr.request_path = mr.request.path
+  mr.request_path = '/'
   return mr
 
 
@@ -67,7 +62,7 @@
         usergroup=fake.UserGroupService(),
         project_star=fake.ProjectStarService(),
         user_star=fake.UserStarService())
-    self.servlet = userprofile.UserProfile('req', 'res', services=services)
+    self.servlet = userprofile.UserProfile(services=services)
 
     for user_id in (
         REGULAR_USER_ID, ADMIN_USER_ID, OTHER_USER_ID):
@@ -111,7 +106,7 @@
   def assertProjectsAnyOrder(self, value_to_test, *expected_project_names):
     actual_project_names = [project_view.project_name
                             for project_view in value_to_test]
-    self.assertItemsEqual(expected_project_names, actual_project_names)
+    six.assertCountEqual(self, expected_project_names, actual_project_names)
 
   def testGatherPageData_RegularUserViewingOtherUserProjects(self):
     """A user can see the other users' live projects, but not archived ones."""
@@ -125,13 +120,15 @@
                                 'other-owner-live')
     self.assertProjectsAnyOrder(page_data['committer_of_projects'],
                                 'other-member-live')
-    self.assertFalse(page_data['owner_of_archived_projects'])
+    self.assertProjectsAnyOrder(
+        page_data['owner_of_archived_projects'], 'other-owner-archived')
     self.assertEqual('ot...@xyz.com', page_data['viewed_user_display_name'])
     self.assertEqual(ezt.boolean(False), page_data['can_delete_user'])
     self.mock_guspd.assert_called_once_with(
         111, mr.viewed_user_auth.user_view, mr.viewed_user_auth.user_pb,
         None)
 
+  @pytest.mark.skip(reason='Test is flaky (https://crbug.com/monorail/12052)')
   def testGatherPageData_RegularUserViewingOwnProjects(self):
     """A user can see all their own projects: live or archived."""
     mr = MakeReqInfo(
diff --git a/sitewide/test/usersettings_test.py b/sitewide/test/usersettings_test.py
index dd7d252..5675846 100644
--- a/sitewide/test/usersettings_test.py
+++ b/sitewide/test/usersettings_test.py
@@ -1,13 +1,13 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Tests for the user settings page."""
 from __future__ import print_function
 from __future__ import division
 from __future__ import absolute_import
 
+import six
 import unittest
 
 try:
@@ -18,7 +18,7 @@
 from framework import framework_helpers
 from framework import permissions
 from framework import template_helpers
-from proto import user_pb2
+from mrproto import user_pb2
 from services import service_manager
 from sitewide import usersettings
 from testing import fake
@@ -58,10 +58,11 @@
     mr = testing_helpers.MakeMonorailRequest()
     page_data = self.servlet.GatherPageData(mr)
 
-    self.assertItemsEqual(
-        ['logged_in_user_pb', 'unified', 'user_tab_mode',
-         'viewed_user', 'offer_saved_queries_subtab', 'viewing_self'],
-        list(page_data.keys()))
+    six.assertCountEqual(
+        self, [
+            'logged_in_user_pb', 'unified', 'user_tab_mode', 'viewed_user',
+            'offer_saved_queries_subtab', 'viewing_self'
+        ], list(page_data.keys()))
     self.assertEqual(template_helpers.PBProxy(mr.auth.user_pb),
                      page_data['logged_in_user_pb'])
 
diff --git a/sitewide/test/userupdates_test.py b/sitewide/test/userupdates_test.py
index 725b123..d024755 100644
--- a/sitewide/test/userupdates_test.py
+++ b/sitewide/test/userupdates_test.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Unittests for monorail.sitewide.userupdates."""
 from __future__ import print_function
@@ -47,7 +46,7 @@
     self.mox.ResetAll()
 
   def testUserUpdatesProjects(self):
-    uup = userupdates.UserUpdatesProjects(None, None, self.services)
+    uup = userupdates.UserUpdatesProjects(self.services)
 
     self.mox.StubOutWithMock(sitewide_helpers, 'GetViewableStarredProjects')
     sitewide_helpers.GetViewableStarredProjects(
@@ -73,7 +72,7 @@
     self.assertEqual(uup._TAB_MODE, page_data['user_updates_tab_mode'])
 
   def testUserUpdatesDevelopers(self):
-    uud = userupdates.UserUpdatesDevelopers(None, None, self.services)
+    uud = userupdates.UserUpdatesDevelopers(self.services)
 
     self.mox.StubOutWithMock(self.services.user_star, 'LookupStarredItemIDs')
     self.services.user_star.LookupStarredItemIDs(
@@ -97,7 +96,7 @@
     self.assertEqual(uud._TAB_MODE, page_data['user_updates_tab_mode'])
 
   def testUserUpdatesIndividual(self):
-    uui = userupdates.UserUpdatesIndividual(None, None, self.services)
+    uui = userupdates.UserUpdatesIndividual(self.services)
 
     self.mox.StubOutWithMock(activities, 'GatherUpdatesData')
     activities.GatherUpdatesData(
diff --git a/sitewide/userclearbouncing.py b/sitewide/userclearbouncing.py
index 0ae5f4a..bdfe86e 100644
--- a/sitewide/userclearbouncing.py
+++ b/sitewide/userclearbouncing.py
@@ -1,18 +1,15 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Class to show a servlet to clear a user's bouncing email timestamp."""
 from __future__ import print_function
 from __future__ import division
 from __future__ import absolute_import
 
-import logging
 import time
 
 from framework import framework_helpers
-from framework import flaskservlet
 from framework import permissions
 from framework import servlet
 from framework import timestr
@@ -62,8 +59,8 @@
         mr, mr.viewed_user_auth.user_view.profile_url, include_project=False,
         saved=1, ts=int(time.time()))
 
-  # def GetUserClearBouncingPage(self, **kwargs):
-  #   return self.handler(**kwargs)
+  def GetUserClearBouncingPage(self, **kwargs):
+    return self.handler(**kwargs)
 
-  # def PostUserClearBouncingPage(self, **kwargs):
-  #   return self.handler(**kwargs)
+  def PostUserClearBouncingPage(self, **kwargs):
+    return self.handler(**kwargs)
diff --git a/sitewide/userprofile.py b/sitewide/userprofile.py
index 2723e9e..33045c4 100644
--- a/sitewide/userprofile.py
+++ b/sitewide/userprofile.py
@@ -1,14 +1,12 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Classes for the user profile page ("my page")."""
 from __future__ import print_function
 from __future__ import division
 from __future__ import absolute_import
 
-import logging
 import time
 import json
 
@@ -17,14 +15,12 @@
 import settings
 from businesslogic import work_env
 from framework import framework_helpers
-from framework import flaskservlet
 from framework import framework_views
 from framework import permissions
 from framework import servlet
 from framework import timestr
 from framework import xsrf
 from project import project_views
-from sitewide import sitewide_helpers
 
 
 class UserProfile(servlet.Servlet):
@@ -231,11 +227,11 @@
         mr, mr.viewed_user_auth.user_view.profile_url, include_project=False,
         saved=1, ts=int(time.time()))
 
-  # def GetUserProfilePage(self, **kwargs):
-  #   return self.handler(**kwargs)
+  def GetUserProfilePage(self, **kwargs):
+    return self.handler(**kwargs)
 
-  # def PostUserProfilePage(self, **kwargs):
-  #   return self.handler(**kwargs)
+  def PostUserProfilePage(self, **kwargs):
+    return self.handler(**kwargs)
 
 
 def _ComputePossibleParentAccounts(
@@ -252,6 +248,7 @@
   found_emails = [user.email for user in found_users]
   return found_emails
 
+
 class BanUser(servlet.Servlet):
   """Bans or un-bans a user."""
 
@@ -270,5 +267,5 @@
         mr, mr.viewed_user_auth.user_view.profile_url, include_project=False,
         saved=1, ts=int(time.time()))
 
-  # def PostBanUserPage(self, **kwargs):
-  #   return self.handler(**kwargs)
+  def PostBanUserPage(self, **kwargs):
+    return self.handler(**kwargs)
diff --git a/sitewide/usersettings.py b/sitewide/usersettings.py
index 163d731..67c8cea 100644
--- a/sitewide/usersettings.py
+++ b/sitewide/usersettings.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Classes for the user settings (preferences) page."""
 from __future__ import print_function
@@ -14,14 +13,14 @@
 import ezt
 
 from businesslogic import work_env
-from framework import flaskservlet
 from framework import framework_helpers
 from framework import permissions
+from framework import servlet
 from framework import template_helpers
 from framework import urls
 
 
-class UserSettings(flaskservlet.FlaskServlet):
+class UserSettings(servlet.Servlet):
   """Shows a page with a simple form to edit user preferences."""
 
   _PAGE_TEMPLATE = 'sitewide/user-settings-page.ezt'
diff --git a/sitewide/userupdates.py b/sitewide/userupdates.py
index b970614..d7a74c9 100644
--- a/sitewide/userupdates.py
+++ b/sitewide/userupdates.py
@@ -1,7 +1,6 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file or at
-# https://developers.google.com/open-source/licenses/bsd
+# Copyright 2016 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 """Classes for user updates pages.
 
@@ -22,9 +21,7 @@
 from businesslogic import work_env
 from features import activities
 from framework import servlet
-from framework import flaskservlet
 from framework import urls
-from sitewide import sitewide_helpers
 
 
 class AbstractUserUpdatesPage(servlet.Servlet):
@@ -88,8 +85,8 @@
           viewed_user_id=mr.viewed_user_auth.user_id)
     return [project.project_id for project in starred_projects]
 
-  # def GetUserUpdatesProjectsPage(self, **kwargs):
-  #   return self.handler(**kwargs)
+  def GetUserUpdatesProjectsPage(self, **kwargs):
+    return self.handler(**kwargs)
 
 
 class UserUpdatesDevelopers(AbstractUserUpdatesPage):
@@ -108,8 +105,8 @@
     logging.debug('StarredUsers: %r', user_ids)
     return user_ids
 
-  # def GetUserUpdatesDevelopersPage(self, **kwargs):
-  #   return self.handler(**kwargs)
+  def GetUserUpdatesDevelopersPage(self, **kwargs):
+    return self.handler(**kwargs)
 
 
 class UserUpdatesIndividual(AbstractUserUpdatesPage):
@@ -124,5 +121,5 @@
     """Returns a list of user IDs whom to retrieve activities from."""
     return [mr.viewed_user_auth.user_id]
 
-  # def GetUserUpdatesPage(self, **kwargs):
-  #   return self.handler(**kwargs)
+  def GetUserUpdatesPage(self, **kwargs):
+    return self.handler(**kwargs)