# This library is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this library; if not, see <http://www.gnu.org/licenses/>.
"""
Koji Smoky Dingo - CLI User Commands
:author: Christopher O'Brien <obriencj@gmail.com>
:license: GPL v3
"""
from koji import ClientSession
from operator import itemgetter
from typing import Optional, Union
from . import AnonSmokyDingo, int_or_str, pretty_json
from ..types import (
    AuthType, TaskState, UserInfo, UserSpec, UserStatus, UserType, )
from ..users import (
    collect_cgs, collect_perminfo, collect_userinfo, )
__all__ = (
    "ShowCGInfo",
    "ShowPermissionInfo",
    "ShowUserInfo",
    "cli_cginfo",
    "cli_perminfo",
    "cli_userinfo",
    "get_userauth_str",
    "get_userstatus_str",
    "get_usertype_str",
)
[docs]
def get_usertype_str(userinfo: UserInfo) -> str:
    """
    Provide a human-readable label for the koji user type enum value
    in a koji user info dict.
    :param userinfo: user info
    :since: 1.0
    """
    val = userinfo.get("usertype") or UserType.NORMAL
    if val == UserType.NORMAL:
        return "NORMAL (user)"
    elif val == UserType.HOST:
        return "HOST (builder)"
    elif val == UserType.GROUP:
        return "GROUP"
    else:
        return f"Unknown ({val})" 
[docs]
def get_userstatus_str(userinfo: UserInfo) -> str:
    """
    Provide a human-readable label for the koji user status enum value
    in a koji user info dict.
    :param userinfo: user info
    :since: 1.0
    """
    val = userinfo.get("status") or UserStatus.NORMAL
    if val == UserStatus.NORMAL:
        return "NORMAL (enabled)"
    elif val == UserStatus.BLOCKED:
        return "BLOCKED (disabled)"
    else:
        return f"Unknown ({val})" 
[docs]
def get_userauth_str(userinfo: UserInfo) -> Optional[str]:
    """
    Provide a human-readable label for the koji auth type enum value
    in a koji user info dict. Returns None if the auth
    :param userinfo: user info
    :since: 2.0
    """
    val = userinfo.get("authtype")
    if val is None:
        return None
    elif val == AuthType.GSSAPI:
        return "GSSAPI"
    elif val == AuthType.KERB:
        return "Kerberos ticket"
    elif val == AuthType.NORMAL:
        return "Password"
    elif val == AuthType.SSL:
        return "SSL certificate"
    else:
        return f"Unknown ({val})" 
[docs]
def cli_userinfo(
        session: ClientSession,
        user: UserSpec,
        stats: bool = False,
        json: bool = False):
    """
    Implements the ``koji userinfo`` command
    :param session: an active koji client session
    :param user: user specification to output information about
    :param stats: include simple user stats
    :param json: produce JSON output
    :raises NoSuchUser: if the user specification doesn't correlate to
      a known user
    :since: 1.0
    """
    userinfo = collect_userinfo(session, user, stats, members=True)
    if json:
        pretty_json(userinfo)
        return
    print(f"User: {userinfo['name']} [{userinfo['id']}]")
    auth = get_userauth_str(userinfo)
    if auth:
        print("Authentication method:", auth)
    krb_princs = userinfo.get("krb_principals", None)
    if krb_princs:
        print("Kerberos principals:")
        for kp in sorted(krb_princs):
            print(" ", kp)
    print("Type:", get_usertype_str(userinfo))
    print("Status:", get_userstatus_str(userinfo))
    cgs = userinfo.get("content_generators", None)
    if cgs:
        print("Content generators:")
        for cg in sorted(cgs, key=itemgetter("name")):
            print(f"{cg['name']} [{cg['id']}]")
    groups = userinfo.get("ksd_groups", None)
    if groups:
        print("Groups:")
        for group in sorted(groups, key=lambda m: m.get("name")):
            print(f"  {group['name']} [{group['id']}]")
    perms = userinfo.get("permissions", None)
    if perms:
        print("Permissions:")
        for perm in sorted(perms):
            print(" ", perm)
    members = userinfo.get("ksd_members", None)
    if members:
        print("Members:")
        for member in sorted(members, key=lambda m: m.get("name")):
            print(f"  {member['name']} [{member['id']}]")
    data = userinfo.get("statistics", None)
    if data:
        print("Statistics:")
        print("  Owned packages:", data.get("package_count", 0))
        print("  Submitted tasks:", data.get("task_count", 0))
        print("  Created builds:", data.get("build_count", 0))
        tdat = data.get("last_task")
        if tdat:
            print(f"  Last task: {tdat['method']} [{tdat['id']}]"
                  f" {tdat['create_time'].split('.')[0]}")
        bdat = data.get("last_build")
        if bdat:
            print(f"  Last build: {bdat['nvr']} [{bdat['build_id']}]"
                  f" {bdat['creation_time'].split('.')[0]}") 
[docs]
class ShowUserInfo(AnonSmokyDingo):
    group = "info"
    description = "Show information about a user or group"
[docs]
    def arguments(self, parser):
        addarg = parser.add_argument
        addarg("user", action="store", type=int_or_str, metavar="USER",
               help="User name or principal")
        addarg("--stats", action="store_true", default=False,
               help="Include user statistics")
        addarg("--json", action="store_true", default=False,
               help="Output information as JSON")
        return parser 
[docs]
    def handle(self, options):
        return cli_userinfo(self.session, options.user,
                            stats=options.stats,
                            json=options.json) 
 
[docs]
def cli_perminfo(
        session: ClientSession,
        permission: str,
        verbose: bool = False,
        by_date: bool = False,
        json: bool = False):
    """
    Implements the ``koji perminfo`` command
    :param session: an active koji client session
    :param permission: the permission name to display information about
    :param verbose: also display who granted the permission and when
    :param by_date: sort the user list by the date they were granted the
      permission
    :param json: output the data as JSON
    :since: 1.0
    """
    perminfo = collect_perminfo(session, permission)
    if json:
        pretty_json(perminfo)
        return
    print("Permission: {name} [{id}]".format(**perminfo))
    users = perminfo["users"]
    if users:
        print("Users:")
        if verbose:
            fmt = "  {user_name} [by {creator_name} on {create_date}]"
        else:
            fmt = "  {user_name}"
        orderkey = itemgetter("create_event" if by_date else "user_name")
        for user in sorted(users, key=orderkey):
            print(fmt.format(**user)) 
[docs]
class ShowPermissionInfo(AnonSmokyDingo):
    description = "Show information about a permission"
[docs]
    def arguments(self, parser):
        addarg = parser.add_argument
        addarg("permission", action="store", metavar="PERMISSION",
               type=int_or_str,
               help="Name of permission")
        addarg("--verbose", "-v", action="store_true", default=False,
               help="Also show who granted the permission and when")
        addarg("--by-date", "-d", action="store_true", default=False,
               help="Sory users by date granted. Otherwise, sort by name")
        addarg("--json", action="store_true", default=False,
               help="Output information as JSON")
        return parser 
[docs]
    def handle(self, options):
        return cli_perminfo(self.session, options.permission,
                            verbose=options.verbose,
                            by_date=options.by_date,
                            json=options.json) 
 
[docs]
def cli_cginfo(
        session: ClientSession,
        name: Optional[str] = None,
        json: bool = False):
    """
    Implements the ``koji cginfo`` command
    :param session: an active koji client session
    :param name: only display information about the content generator with
      this name
    :param json: output the data as JSON
    :since: 1.0
    """
    cgs = collect_cgs(session, name=name)
    if json:
        pretty_json(cgs)
        return
    for cginfo in sorted(cgs, key=itemgetter("id")):
        print("Content generator: {name} [{id}]".format(**cginfo))
        users = cginfo.get("users")
        if users:
            print("Users:")
            for user in sorted(users):
                print(" ", user)
        print() 
[docs]
class ShowCGInfo(AnonSmokyDingo):
    description = "List content generators and their users"
[docs]
    def arguments(self, parser):
        addarg = parser.add_argument
        addarg("--name", action="store", default=None,
               help="Only show the given content generator")
        addarg("--json", action="store_true", default=False,
               help="Output information as JSON")
        return parser 
[docs]
    def handle(self, options):
        return cli_cginfo(self.session,
                          name=options.name,
                          json=options.json) 
 
#
# The end.