# 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

"""A class to display a user group, including a paginated list of members."""
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import

import logging
import time

import ezt

from framework import exceptions
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 sitewide import group_helpers
from sitewide import sitewide_views

MEMBERS_PER_PAGE = 50


class GroupDetail(servlet.Servlet):
  """The group detail page presents information about one user group."""

  _PAGE_TEMPLATE = 'sitewide/group-detail-page.ezt'

  def AssertBasePermission(self, mr):
    """Assert that the user has the permissions needed to view this page."""
    super(GroupDetail, self).AssertBasePermission(mr)

    group_id = mr.viewed_user_auth.user_id
    group_settings = self.services.usergroup.GetGroupSettings(
        mr.cnxn, group_id)
    if not group_settings:
      return

    member_ids, owner_ids = self.services.usergroup.LookupAllMembers(
          mr.cnxn, [group_id])
    (owned_project_ids, membered_project_ids,
     contrib_project_ids) = self.services.project.GetUserRolesInAllProjects(
         mr.cnxn, mr.auth.effective_ids)
    project_ids = owned_project_ids.union(
        membered_project_ids).union(contrib_project_ids)
    if not permissions.CanViewGroupMembers(
        mr.perms, mr.auth.effective_ids, group_settings, member_ids[group_id],
        owner_ids[group_id], project_ids):
      raise permissions.PermissionException(
          'User is not allowed to view a user group')

  def GatherPageData(self, mr):
    """Build up a dictionary of data values to use when rendering the page."""
    group_id = mr.viewed_user_auth.user_id
    group_settings = self.services.usergroup.GetGroupSettings(
        mr.cnxn, group_id)
    if not group_settings:
      raise exceptions.NoSuchGroupException()

    member_ids_dict, owner_ids_dict = (
        self.services.usergroup.LookupVisibleMembers(
            mr.cnxn, [group_id], mr.perms, mr.auth.effective_ids,
            self.services))
    member_ids = member_ids_dict[group_id]
    owner_ids = owner_ids_dict[group_id]
    member_pbs_dict = self.services.user.GetUsersByIDs(
        mr.cnxn, member_ids)
    owner_pbs_dict = self.services.user.GetUsersByIDs(
        mr.cnxn, owner_ids)
    member_dict = {}
    for user_id, user_pb in member_pbs_dict.items():
      member_view = group_helpers.GroupMemberView(user_pb, group_id, 'member')
      member_dict[user_id] = member_view
    owner_dict = {}
    for user_id, user_pb in owner_pbs_dict.items():
      member_view = group_helpers.GroupMemberView(user_pb, group_id, 'owner')
      owner_dict[user_id] = member_view

    member_user_views = []
    member_user_views.extend(
        sorted(list(owner_dict.values()), key=lambda u: u.email))
    member_user_views.extend(
        sorted(list(member_dict.values()), key=lambda u: u.email))

    group_view = sitewide_views.GroupView(
        mr.viewed_user_auth.email, len(member_ids), group_settings,
        mr.viewed_user_auth.user_id)
    url_params = [(name, mr.GetParam(name)) for name in
                  framework_helpers.RECOGNIZED_PARAMS]
    pagination = paginate.ArtifactPagination(
        member_user_views, mr.GetPositiveIntParam('num', MEMBERS_PER_PAGE),
        mr.GetPositiveIntParam('start'), mr.project_name, group_view.detail_url,
        url_params=url_params)

    is_imported_group = bool(group_settings.ext_group_type)

    offer_membership_editing = permissions.CanEditGroup(
        mr.perms, mr.auth.effective_ids, owner_ids) and not is_imported_group

    group_type = 'Monorail user group'
    if group_settings.ext_group_type:
      group_type = str(group_settings.ext_group_type).capitalize()

    return {
        'admin_tab_mode': self.ADMIN_TAB_META,
        'offer_membership_editing': ezt.boolean(offer_membership_editing),
        'initial_add_members': '',
        'initially_expand_form': ezt.boolean(False),
        'groupid': group_id,
        'groupname': mr.viewed_username,
        'settings': group_settings,
        'group_type': group_type,
        'pagination': pagination,
        }

  def ProcessFormData(self, mr, post_data):
    """Process the posted form."""
    _, owner_ids_dict = self.services.usergroup.LookupMembers(
        mr.cnxn, [mr.viewed_user_auth.user_id])
    owner_ids = owner_ids_dict[mr.viewed_user_auth.user_id]
    permit_edit = permissions.CanEditGroup(
        mr.perms, mr.auth.effective_ids, owner_ids)
    if not permit_edit:
      raise permissions.PermissionException(
          'User is not permitted to edit group membership')

    group_settings = self.services.usergroup.GetGroupSettings(
        mr.cnxn, mr.viewed_user_auth.user_id)
    if bool(group_settings.ext_group_type):
      raise permissions.PermissionException(
          'Imported groups are read-only')

    if 'addbtn' in post_data:
      return self.ProcessAddMembers(mr, post_data)
    elif 'removebtn' in post_data:
      return self.ProcessRemoveMembers(mr, post_data)

  def ProcessAddMembers(self, mr, post_data):
    """Process the user's request to add members.

    Args:
      mr: common information parsed from the HTTP request.
      post_data: dictionary of form data.

    Returns:
      String URL to redirect the user to after processing.
    """
    # 1. Gather data from the request.
    group_id = mr.viewed_user_auth.user_id
    add_members_str = post_data.get('addmembers')
    new_member_ids = project_helpers.ParseUsernames(
        mr.cnxn, self.services.user, add_members_str)
    role = post_data['role']

    # 2. Call services layer to save changes.
    if not mr.errors.AnyErrors():
      try:
        self.services.usergroup.UpdateMembers(
            mr.cnxn, group_id, new_member_ids, role)
      except exceptions.CircularGroupException:
        mr.errors.addmembers = (
            'The members are already ancestors of current group.')

    # 3. Determine the next page in the UI flow.
    if mr.errors.AnyErrors():
      self.PleaseCorrect(
          mr, initial_add_members=add_members_str,
          initially_expand_form=ezt.boolean(True))
    else:
      return framework_helpers.FormatAbsoluteURL(
          mr, '/g/%s/' % mr.viewed_username, include_project=False,
          saved=1, ts=int(time.time()))

  def ProcessRemoveMembers(self, mr, post_data):
    """Process the user's request to remove members.

    Args:
      mr: common information parsed from the HTTP request.
      post_data: dictionary of form data.

    Returns:
      String URL to redirect the user to after processing.
    """
    # 1. Gather data from the request.
    remove_strs = post_data.getall('remove')
    logging.info('remove_strs = %r', remove_strs)

    if not remove_strs:
      mr.errors.remove = 'No users specified'

    # 2. Call services layer to save changes.
    if not mr.errors.AnyErrors():
      remove_ids = set(
          self.services.user.LookupUserIDs(mr.cnxn, remove_strs).values())
      self.services.usergroup.RemoveMembers(
          mr.cnxn, mr.viewed_user_auth.user_id, remove_ids)

    # 3. Determine the next page in the UI flow.
    if mr.errors.AnyErrors():
      self.PleaseCorrect(mr)
    else:
      return framework_helpers.FormatAbsoluteURL(
          mr, '/g/%s/' % mr.viewed_username, include_project=False,
          saved=1, ts=int(time.time()))
