<commit_before>#    This file is part of rhizi, a collaborative knowledge graph editor.
#    Copyright (C) 2014-2015  Rhizi
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program 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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import argparse
import os
import pickle
import pwd
import re
import sys
from getpass import getpass

from six import u

from .. crypt_util import hash_pw
from .. rz_start import init_config
from .. rz_user import User_Account
from .. rz_user_db import User_DB

verbose = False

python2 = sys.version_info[0] == 2


def add_user_login(user_db, salt, first_name, last_name,
                   rz_username, email_address, pw_plaintext):

    pw_hash = hash_pw(str(pw_plaintext), salt)
    u_account = User_Account(first_name=first_name,
                             last_name=last_name,
                             rz_username=rz_username,
                             email_address=email_address,
                             pw_hash=pw_hash,
                             role_set=['user'])
    user_db.user_add(u_account)


def init_pw_db(cfg, user_pw_list_file, user_db_path, ugid_str='www-data'):
    """
    @param ugid_str: shared uid, gid set on generated file
    """

    if os.path.exists(user_db_path):
        print('user_db_path already exists, aborting: ' + user_db_path)
        return

    user_db = User_DB(db_path=user_db_path)
    user_db.init(mode='n')  # always create a new, empty database, open for reading and writing

    assert len(cfg.secret_key) > 8, 'server-key not found or too short'
    print('using config secret_key for salt generation: ' + cfg.secret_key[:3] + '...')

    u_count = 0
    if user_pw_list_file is not None:
        with open(user_pw_list_file, 'r') as f:
            for line in f:
                if re.match('(^#)|(\s+$)', line):
                    continue

                kv_arr = line.split(',')
                if 5 != len(kv_arr):
                    raise Exception('failed to parse first-name,last-name,email,user,pw line: ' + line)

                first_name, last_name, rz_username, email_address, pw_plaintext = map(str.strip, kv_arr)
                add_user_login(user_db=user_db,
                            self=cfg.secret_key,
                            first_name=first_name,
                            last_name=last_name,
                            rz_username=rz_username,
                            email_address=email_address,
                            pw_plaintext=pw_plaintext)

                print('user_db: added entry: rz_username: %s, pw: %s...' % (rz_username, pw_plaintext[:3]))
                u_count = u_count + 1

    user_db.shutdown()

    ugid = pwd.getpwnam(ugid_str).pw_uid
    os.chown(user_db_path, ugid, ugid)

    print('user_db generated: path: %s, user-count: %d' % (user_db_path, u_count))

def open_existing_user_db(user_db_path):
    user_db = User_DB(db_path=user_db_path)
    user_db.init(mode='w')
    return user_db

def role_add(user_db_path, user_email, role):
    user_db = open_existing_user_db(user_db_path)
    uid, u = user_db.lookup_user__by_email_address(user_email)
    user_db.user_add_role(uid, role)

def role_rm(user_db_path, user_email, role):
    user_db = open_existing_user_db(user_db_path)
    uid, u = user_db.lookup_user__by_email_address(user_email)
    user_db.user_rm_role(uid, role)


def list_users(user_db_path):
    user_db = open_existing_user_db(user_db_path)
    if verbose:
        print("{}: {} entries".format(user_db_path, len(user_db)))
    headers = ['first_name', 'last_name', 'rz_username', 'email_address', 'role_set']
    print(", ".join(headers))
    if python2:
        for i, user in user_db:
            utf = list(getattr(user, hdr) for hdr in headers[:-1]) # .decode('utf-8')
            nonutf = list(getattr(user, hdr) for hdr in headers[-1:])
            print(u'{}, {}, {}, {}, {}'.format(*(utf + nonutf)).encode('utf-8'))
    else:
        for i, user in user_db:
            params = list(getattr(user, hdr) for hdr in headers)
            print(u'{}, {}, {}, {}, {}'.format(*params))


def add_user(user_db_path, cfg, email, password, first, last, username):
    user_db = open_existing_user_db(user_db_path)
    add_user_login(user_db=user_db,
                   salt=cfg.secret_key,
                   first_name=first,
                   last_name=last,
                   rz_username=username,
                   email_address=email,
                   pw_plaintext=password)


def remove_user(user_db_path, cfg, email):
    user_db = open_existing_user_db(user_db_path)
    uid, u = user_db.lookup_user__by_email_address(email)
    user_db.user_rm(uid)


def update_user(user_db_path, cfg, email, password, first, last, username):
    """ note: password shouldn't be passed through arguments, should be queried from
    stdin or read from a file
    """
    user_db = open_existing_user_db(user_db_path)
    uid, u = user_db.lookup_user__by_email_address(email)
    user_db.update(uid=uid, first_name=first, last_name=last, email_address=email,
                   rz_username=username)


def main():
    global verbose
    commands = ['init', 'role-add', 'role-rm', 'list', 'add', 'remove', 'update']
    p = argparse.ArgumentParser(description='rz-cli tool. You must provide a command, one of:\n{}'.format(commands))
    p.add_argument('--config-dir', help='path to Rhizi config dir', default='res/etc')
    p.add_argument('--user-db-path', help='path to user_db (ignore config)')
    p.add_argument('--user-db-init-file', help='user_db db initialization file in \'user,pw\' format')
    p.add_argument('--email', help='email of user to operate on')
    p.add_argument('--role', help='role to add or remove to/from user, i.e. admin or user')
    p.add_argument('--first-name', help="first name for added user")
    p.add_argument('--last-name', help='last name for added user')
    p.add_argument('--username', help='username for added user')
    p.add_argument('--password-file', help='provide file whose contents is the password')
    p.add_argument('--user-db-ugid', default='www-data')
    p.add_argument('--verbose', help='print extra output', default=False, action='store_true')

    args, rest = p.parse_known_args()
    verbose = args.verbose
    illegal = False
    if len(rest) != 1:
        print("only one non argument parameter expected. got {}".format(repr(rest)))
        illegal = True
    elif rest[0] not in commands:
        print("command not in {}".format(commands))
        illegal = True
    elif rest[0] in ['role-add', 'role-rm'] and not args.email:
        print("command {} requires an email argument".format(command))
        illegal = True
    elif rest[0] == 'add' and None in {args.first_name, args.last_name, args.username}:
        print("missing one of first-name, last-name or username for user addition")
        illegal = True
    elif rest[0] == 'remove' and None == args.email:
        print("missing email for user removal")
        illegal = True
    elif rest[0] == 'update' and (None == args.email or {None} == {args.first_name, args.last_name, args.username, args.password_file}):
        print("missing either email or one of first/last/username for update")
        illegal = True
    if illegal:
        p.print_help()
        raise SystemExit

    command = rest[0]
    cfg = init_config(args.config_dir)
    user_db_path = args.user_db_path if args.user_db_path is not None else cfg.user_db_path

    if command in {'add', 'update'}:<commit_msg>rz-user-tool: print path db is read from<commit_after>#    This file is part of rhizi, a collaborative knowledge graph editor.
#    Copyright (C) 2014-2015  Rhizi
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program 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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import argparse
import os
import pickle
import pwd
import re
import sys
from getpass import getpass

from six import u

from .. crypt_util import hash_pw
from .. rz_start import init_config
from .. rz_user import User_Account
from .. rz_user_db import User_DB

verbose = False

python2 = sys.version_info[0] == 2


def add_user_login(user_db, salt, first_name, last_name,
                   rz_username, email_address, pw_plaintext):

    pw_hash = hash_pw(str(pw_plaintext), salt)
    u_account = User_Account(first_name=first_name,
                             last_name=last_name,
                             rz_username=rz_username,
                             email_address=email_address,
                             pw_hash=pw_hash,
                             role_set=['user'])
    user_db.user_add(u_account)


def init_pw_db(cfg, user_pw_list_file, user_db_path, ugid_str='www-data'):
    """
    @param ugid_str: shared uid, gid set on generated file
    """

    if os.path.exists(user_db_path):
        print('user_db_path already exists, aborting: ' + user_db_path)
        return

    user_db = User_DB(db_path=user_db_path)
    user_db.init(mode='n')  # always create a new, empty database, open for reading and writing

    assert len(cfg.secret_key) > 8, 'server-key not found or too short'
    print('using config secret_key for salt generation: ' + cfg.secret_key[:3] + '...')

    u_count = 0
    if user_pw_list_file is not None:
        with open(user_pw_list_file, 'r') as f:
            for line in f:
                if re.match('(^#)|(\s+$)', line):
                    continue

                kv_arr = line.split(',')
                if 5 != len(kv_arr):
                    raise Exception('failed to parse first-name,last-name,email,user,pw line: ' + line)

                first_name, last_name, rz_username, email_address, pw_plaintext = map(str.strip, kv_arr)
                add_user_login(user_db=user_db,
                            self=cfg.secret_key,
                            first_name=first_name,
                            last_name=last_name,
                            rz_username=rz_username,
                            email_address=email_address,
                            pw_plaintext=pw_plaintext)

                print('user_db: added entry: rz_username: %s, pw: %s...' % (rz_username, pw_plaintext[:3]))
                u_count = u_count + 1

    user_db.shutdown()

    ugid = pwd.getpwnam(ugid_str).pw_uid
    os.chown(user_db_path, ugid, ugid)

    print('user_db generated: path: %s, user-count: %d' % (user_db_path, u_count))

def open_existing_user_db(user_db_path):
    user_db = User_DB(db_path=user_db_path)
    user_db.init(mode='w')
    return user_db

def role_add(user_db_path, user_email, role):
    user_db = open_existing_user_db(user_db_path)
    uid, u = user_db.lookup_user__by_email_address(user_email)
    user_db.user_add_role(uid, role)

def role_rm(user_db_path, user_email, role):
    user_db = open_existing_user_db(user_db_path)
    uid, u = user_db.lookup_user__by_email_address(user_email)
    user_db.user_rm_role(uid, role)


def list_users(user_db_path):
    user_db = open_existing_user_db(user_db_path)
    if verbose:
        print("{}: {} entries".format(user_db_path, len(user_db)))
    headers = ['first_name', 'last_name', 'rz_username', 'email_address', 'role_set']
    print(", ".join(headers))
    if python2:
        for i, user in user_db:
            utf = list(getattr(user, hdr) for hdr in headers[:-1]) # .decode('utf-8')
            nonutf = list(getattr(user, hdr) for hdr in headers[-1:])
            print(u'{}, {}, {}, {}, {}'.format(*(utf + nonutf)).encode('utf-8'))
    else:
        for i, user in user_db:
            params = list(getattr(user, hdr) for hdr in headers)
            print(u'{}, {}, {}, {}, {}'.format(*params))


def add_user(user_db_path, cfg, email, password, first, last, username):
    user_db = open_existing_user_db(user_db_path)
    add_user_login(user_db=user_db,
                   salt=cfg.secret_key,
                   first_name=first,
                   last_name=last,
                   rz_username=username,
                   email_address=email,
                   pw_plaintext=password)


def remove_user(user_db_path, cfg, email):
    user_db = open_existing_user_db(user_db_path)
    uid, u = user_db.lookup_user__by_email_address(email)
    user_db.user_rm(uid)


def update_user(user_db_path, cfg, email, password, first, last, username):
    """ note: password shouldn't be passed through arguments, should be queried from
    stdin or read from a file
    """
    user_db = open_existing_user_db(user_db_path)
    uid, u = user_db.lookup_user__by_email_address(email)
    user_db.update(uid=uid, first_name=first, last_name=last, email_address=email,
                   rz_username=username)


def main():
    global verbose
    commands = ['init', 'role-add', 'role-rm', 'list', 'add', 'remove', 'update']
    p = argparse.ArgumentParser(description='rz-cli tool. You must provide a command, one of:\n{}'.format(commands))
    p.add_argument('--config-dir', help='path to Rhizi config dir', default='res/etc')
    p.add_argument('--user-db-path', help='path to user_db (ignore config)')
    p.add_argument('--user-db-init-file', help='user_db db initialization file in \'user,pw\' format')
    p.add_argument('--email', help='email of user to operate on')
    p.add_argument('--role', help='role to add or remove to/from user, i.e. admin or user')
    p.add_argument('--first-name', help="first name for added user")
    p.add_argument('--last-name', help='last name for added user')
    p.add_argument('--username', help='username for added user')
    p.add_argument('--password-file', help='provide file whose contents is the password')
    p.add_argument('--user-db-ugid', default='www-data')
    p.add_argument('--verbose', help='print extra output', default=False, action='store_true')

    args, rest = p.parse_known_args()
    verbose = args.verbose
    illegal = False
    if len(rest) != 1:
        print("only one non argument parameter expected. got {}".format(repr(rest)))
        illegal = True
    elif rest[0] not in commands:
        print("command not in {}".format(commands))
        illegal = True
    elif rest[0] in ['role-add', 'role-rm'] and not args.email:
        print("command {} requires an email argument".format(command))
        illegal = True
    elif rest[0] == 'add' and None in {args.first_name, args.last_name, args.username}:
        print("missing one of first-name, last-name or username for user addition")
        illegal = True
    elif rest[0] == 'remove' and None == args.email:
        print("missing email for user removal")
        illegal = True
    elif rest[0] == 'update' and (None == args.email or {None} == {args.first_name, args.last_name, args.username, args.password_file}):
        print("missing either email or one of first/last/username for update")
        illegal = True
    if illegal:
        p.print_help()
        raise SystemExit

    command = rest[0]
    cfg = init_config(args.config_dir)
    user_db_path = args.user_db_path if args.user_db_path is not None else cfg.user_db_path
    print("user db path: {}".format(user_db_path))

    if command in {'add', 'update'}:
{'fraction_non_alphanumeric': 0.11326681448632668, 'fraction_numerical': 0.003695491500369549, 'mean_word_length': 2.802576112412178, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 6, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4982377', 'n_tokens_mistral': 5210, 'n_tokens_neox': 5079, 'n_words': 1351}