"""

Repo:
    id:                      Repo ID
    name:                    Repo Name
    desc:                    Repo description
    worktree:                The full path of the worktree of the repo
    worktree_changed:        True if the worktree is changed
    worktree_checktime:      The last check time of whether worktree is changed
    head_branch:             The name of the head branch
    enctrypted:              True if the repo is encrypted
    passwd:                  The password
    

Branch:
    name:
    commit_id:
    repo_id:

Commit:
    id:
    creator_name:
    creator:                 The id of the creator
    desc:
    ctime:
    repo_id:
    root_id:
    parent_id:
    second_parent_id:


"""


from datetime import datetime
import json
import logging
import os
import sys
import ConfigParser
from urlparse import urlparse

import ccnet
import seafile
import re
from pysearpc import SearpcError

_DEBUG = 'SEAFILE_DEBUG' in os.environ

ENVIRONMENT_VARIABLES = ('CCNET_CONF_DIR', 'SEAFILE_CONF_DIR')

# Used to fix bug in some rpc calls, will be removed in near future.
MAX_INT = 2147483647            

### Loading ccnet and seafile configurations ###
'''ccnet'''
try:
    CCNET_CONF_PATH = os.environ[ENVIRONMENT_VARIABLES[0]]
    if not CCNET_CONF_PATH: # If it's set but is an empty string.
        raise KeyError
except KeyError:
    raise ImportError("Seaserv cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLES[0])
else:
    if _DEBUG:
        print "Loading ccnet config from " + CCNET_CONF_PATH

CCNET_CONF_PATH = os.path.normpath(os.path.expanduser(CCNET_CONF_PATH))

pool = ccnet.ClientPool(CCNET_CONF_PATH)
ccnet_rpc = ccnet.CcnetRpcClient(pool, req_pool=True)
ccnet_threaded_rpc = ccnet.CcnetThreadedRpcClient(pool, req_pool=True)
monitor_rpc = seafile.MonitorRpcClient(pool)
seafserv_rpc = seafile.ServerRpcClient(pool, req_pool=True)
seafserv_threaded_rpc = seafile.ServerThreadedRpcClient(pool, req_pool=True)

# load ccnet server addr and port from ccnet.conf.
# 'addr:port' is used when downloading a repo
config = ConfigParser.ConfigParser()
config.read(os.path.join(CCNET_CONF_PATH, 'ccnet.conf'))

if config.has_option('General', 'SERVICE_URL'):
    service_url = config.get('General', 'SERVICE_URL')
    hostname = urlparse(service_url).hostname

    SERVICE_URL = service_url
    CCNET_SERVER_ADDR = hostname
    if config.has_option('Network', 'PORT'):
        CCNET_SERVER_PORT = config.get('Network', 'PORT')
    else:
        CCNET_SERVER_PORT = 10001
else:
    print "Warning: SERVICE_URL not set in ccnet.conf"
    CCNET_SERVER_ADDR = None
    CCNET_SERVER_PORT = None
    SERVICE_URL = None

SERVER_ID = config.get('General', 'ID')

'''seafile'''
try:
    SEAFILE_CONF_DIR = os.environ[ENVIRONMENT_VARIABLES[1]]
    if not SEAFILE_CONF_DIR: # If it's set but is an empty string.
        raise KeyError
except KeyError:
    raise ImportError("Seaserv cannot be imported, because environment variable %s is undefined." % ENVIRONMENT_VARIABLES[1])
else:
    if _DEBUG:
        print "Loading seafile config from " + SEAFILE_CONF_DIR

SEAFILE_CONF_DIR = os.path.normpath(os.path.expanduser(SEAFILE_CONF_DIR))
config.read(os.path.join(SEAFILE_CONF_DIR, 'seafile.conf'))

def get_fileserver_option(key, default):
    '''
    "fileserver" used to be "httpserver"
    '''
    for section in ('fileserver', 'httpserver'):
        if config.has_option(section, key):
            return config.get(section, key)

    return default

MAX_UPLOAD_FILE_SIZE = None # Defaults to no limit
try:
    max_upload_size_mb = int(get_fileserver_option('max_upload_size', 0))
    if max_upload_size_mb > 0:
        MAX_UPLOAD_FILE_SIZE = max_upload_size_mb * (2 ** 20)
except ValueError:
    pass

MAX_DOWNLOAD_DIR_SIZE = 100 * (2 ** 20) # Default max size of a downloadable dir
try:
    max_download_dir_size_mb = int(get_fileserver_option('max_download_dir_size', 0))
    if max_download_dir_size_mb > 0:
        MAX_DOWNLOAD_DIR_SIZE = max_download_dir_size_mb * (2 ** 20)
except ValueError:
    pass

FILE_SERVER_PORT = get_fileserver_option('port', '8082')

if CCNET_SERVER_ADDR:
    FILE_SERVER_ROOT = 'http://' + CCNET_SERVER_ADDR + ':' + FILE_SERVER_PORT
else:
    FILE_SERVER_ROOT = None

CALC_SHARE_USAGE = False
if config.has_option('quota', 'calc_share_usage'):
    CALC_SHARE_USAGE = config.getboolean('quota', 'calc_share_usage')

# Get an instance of a logger
logger = logging.getLogger(__name__)

#### Basic ccnet API ####

def get_emailusers(source, start, limit, is_active=None):
    if is_active is True:
        status = "active"       # list active users
    elif is_active is False:
        status = "inactive"     # list inactive users
    else:
        status = ""             # list all users

    return ccnet_threaded_rpc.get_emailusers(source, start, limit, status)

def count_emailusers():
    try:
        ret = ccnet_threaded_rpc.count_emailusers()
    except SearpcError:
        ret = -1
    return 0 if ret < 0 else ret

def get_emailuser_with_import(email):
    return ccnet_threaded_rpc.get_emailuser_with_import(email)

def get_session_info():
    return ccnet_rpc.get_session_info()

# group
def get_group(group_id):
    group_id_int = int(group_id)
    try:
        group = ccnet_threaded_rpc.get_group(group_id_int)
    except SearpcError:
        group = None
    return group

def get_personal_groups(start, limit):
    try:
        groups_all = ccnet_threaded_rpc.get_all_groups(start, limit)
    except SearpcError:
        return []
    return [ x for x in groups_all if not is_org_group(x.id) ]

def get_personal_groups_by_user(email):
    try:
        groups_all = ccnet_threaded_rpc.get_groups(email)
    except SearpcError:
        return []

    return [ x for x in groups_all if not is_org_group(x.id) ]
    
# group user
def is_group_user(group_id, user):
    try:
        ret = ccnet_threaded_rpc.is_group_user(group_id, user)
    except SearpcError:
        ret = 0
    return ret

def check_group_staff(group_id, username):
    """Check where user is group staff"""
    group_id = int(group_id)
    try:
        ret = ccnet_threaded_rpc.check_group_staff(group_id, username)
    except SearpcError, e:
        logger.error(e)
        ret = 0

    return True if ret == 1 else False

def remove_group_user(user):
    """
    Remove group user relationship.
    """
    return ccnet_threaded_rpc.remove_group_user(user)

def get_group_members(group_id, start=-1, limit=-1):
    group_id_int = int(group_id)
    try:
        members = ccnet_threaded_rpc.get_group_members(group_id_int)
    except SearpcError:
        members = []
    return members

# org group
def is_org_group(group_id):
    try:
        ret = ccnet_threaded_rpc.is_org_group(group_id)
    except SearpcError:
        ret = -1
    return True if ret == 1 else False

def get_org_id_by_group(group_id):
    try:
        org_id = ccnet_threaded_rpc.get_org_id_by_group(group_id)
    except SearpcError:
        org_id = -1
    return org_id

def get_org_groups(org_id, start, limit):
    try:
        groups = ccnet_threaded_rpc.get_org_groups(org_id, start, limit)
    except SearpcError:
        groups = []
    return groups

def get_org_groups_by_user(org_id, user):
    """
    Get user's groups in org.
    """
    try:
        groups_all = ccnet_threaded_rpc.get_groups(user)
    except SearpcError:
        return []

    return [ x for x in groups_all if org_id == get_org_id_by_group(x.id) ]
    
# org
def create_org(org_name, url_prefix, username):
    ccnet_threaded_rpc.create_org(org_name, url_prefix, username)

def get_org_by_url_prefix(url_prefix):
    try:
        org = ccnet_threaded_rpc.get_org_by_url_prefix(url_prefix)
    except SearpcError:
        org = None

    return org

def get_org_by_id(org_id):
    try:
        org = ccnet_threaded_rpc.get_org_by_id(org_id)
    except SearpcError:
        org = None

    return org

# org user
def add_org_user(org_id, email, is_staff):
    try:
        ccnet_threaded_rpc.add_org_user(org_id, email, is_staff)
    except SearpcError:
        pass

def remove_org_user(org_id, email):
    try:
        ccnet_threaded_rpc.remove_org_user(org_id, email)
    except SearpcError:
        pass

def org_user_exists(org_id, user):
    try:
        ret = ccnet_threaded_rpc.org_user_exists(org_id, user)
    except SearpcError:
        ret = -1
    return True if ret == 1 else False

def get_org_users_by_url_prefix(url_prefix, start, limit):
    """
    List org users.
    """
    try:
        users = ccnet_threaded_rpc.get_org_emailusers(url_prefix, start, limit)
    except:
        users = []
    return users

def get_orgs_by_user(user):
    try:
        orgs = ccnet_threaded_rpc.get_orgs_by_user(user)
    except SearpcError:
        orgs = []

    return orgs

def is_org_staff(org_id, user):
    """
    Check whether user is staff of a org.
    """
    try:
        ret = ccnet_threaded_rpc.is_org_staff(org_id, user)
    except SearpcError:
        ret = -1
    return True if ret == 1 else False

def get_user_current_org(user, url_prefix):
    orgs = get_orgs_by_user(user)
    for org in orgs:
        if org.url_prefix == url_prefix:
            return org
    return None

def send_command(command):
    client = pool.get_client()
    client.send_cmd(command)
    ret = client.response[2]
    pool.return_client(client)
    return ret

def send_message(msg_type, content):
    client = pool.get_client()
    client.send_message(msg_type, content)
    pool.return_client(client)

def get_binding_peerids(email):
    """Get peer ids of a given email"""
    try:
        peer_ids = ccnet_threaded_rpc.get_binding_peerids(email)
    except SearpcError:
        return []

    if not peer_ids:
        return []
    
    peerid_list = []
    for peer_id in peer_ids.split("\n"):
        if peer_id == '':
            continue
        peerid_list.append(peer_id)
    return peerid_list

######## seafserv API ####

# repo
def get_repos():
    """
    Return repository list.

    """
    return seafserv_threaded_rpc.get_repo_list("", 100)

def get_repo(repo_id):
    return seafserv_threaded_rpc.get_repo(repo_id)

def edit_repo(repo_id, name, desc, user):
    try:
        ret = seafserv_threaded_rpc.edit_repo(repo_id, name, desc, user)
    except SearpcError, e:
        ret = -1
    return True if ret == 0 else False

def create_repo(name, desc, user, passwd):
    """
    Return repo id if successfully created a repo, otherwise None.
    """
    try:
        ret = seafserv_threaded_rpc.create_repo(name, desc, user, passwd)
    except SearpcError, e:
        logger.error(e)
        ret = None
    return ret
    
def remove_repo(repo_id):
    """
    Return true if successfully removed a repo, otherwise false.
    """
    try:
        ret = seafserv_threaded_rpc.remove_repo(repo_id)
    except SearpcError, e:
        logger.error(e)
        ret = -1
    return True if ret == 0 else False

def list_personal_repos_by_owner(owner):
    """
    List users owned repos in personal context.
    """
    try:
        repos = seafserv_threaded_rpc.list_owned_repos(owner)
    except SearpcError:
        repos = []
    return repos

def get_repo_token_nonnull(repo_id, username):
    return seafserv_threaded_rpc.get_repo_token_nonnull (repo_id, username)

def get_repo_owner(repo_id):
    """
    Get owner of a repo.
    """
    try:
        ret = seafserv_threaded_rpc.get_repo_owner(repo_id)
    except SearpcError:
        ret = ''
    return ret
    
def is_repo_owner(user, repo_id):
    """
    Check whether user is repo owner.
    """
    try:
        ret = seafserv_threaded_rpc.is_repo_owner(user, repo_id)
    except SearpcError:
        ret = 0
    return ret

def server_repo_size(repo_id):
    try:
        size = seafserv_threaded_rpc.server_repo_size(repo_id)
    except SearpcError:
        size = 0
    return size

# org repo
def create_org_repo(repo_name, repo_desc, user, passwd, org_id):
    """
    Create org repo, return valid repo id if success.
    """
    try:
        repo_id = seafserv_threaded_rpc.create_org_repo(repo_name, repo_desc,
                                                        user, passwd, org_id)
    except SearpcError:
        repo_id = None
        
    return repo_id

def is_org_repo(repo_id):
    org_id = get_org_id_by_repo_id(repo_id)
    return True if org_id > 0 else False

def list_org_repos_by_owner(org_id, user):
    try:
        repos = seafserv_threaded_rpc.list_org_repos_by_owner(org_id, user)
    except SearpcError:
        repos = []
    return repos

def get_org_repos(org_id, start, limit):
    """
    List repos created in org.
    """
    try:
        repos = seafserv_threaded_rpc.get_org_repo_list(org_id, start, limit)
    except SearpcError:
        repos = []

    if repos:
        for r in repos:
            r.owner = get_org_repo_owner(r.id)
            
    return repos

def get_org_id_by_repo_id(repo_id):
    """
    Get org id according repo id.
    """
    try:
        org_id = seafserv_threaded_rpc.get_org_id_by_repo_id(repo_id)
    except SearpcError:
        org_id = -1
    return org_id

def is_org_repo_owner(org_id, repo_id, user):
    """
    Check whether user is org repo owner.
    NOTE:
    	`org_id` may used in future.
    """
    owner = get_org_repo_owner(repo_id)
    if not owner:
        return False 
    return True if owner == user else False

def get_org_repo_owner(repo_id):
    """
    Get owner of org repo.
    """
    try:
        owner = seafserv_threaded_rpc.get_org_repo_owner(repo_id)
    except SearpcError:
        owner = None
    return owner

# commit
def get_commit(repo_id, repo_version, cmt_id):
    """ Get a commit. """
    try:
        ret = seafserv_threaded_rpc.get_commit(repo_id, repo_version, cmt_id)
    except SearpcError:
        ret = None
    return ret
    
def get_commits(repo_id, offset, limit):
    """Get commit lists."""
    try:
        ret = seafserv_threaded_rpc.get_commit_list(repo_id, offset, limit)
    except SearpcError:
        ret = None
    return ret

# branch
def get_branches(repo_id):
    """Get branches of a given repo"""
    return seafserv_threaded_rpc.branch_gets(repo_id)

# group repo
def get_group_repos_by_owner(user):
    """
    List user's repos that are sharing to groups
    """
    try:
        ret = seafserv_threaded_rpc.get_group_repos_by_owner(user)
    except SearpcError:
        ret = []
    return ret

def get_shared_groups_by_repo(repo_id):
    try:
        group_ids = seafserv_threaded_rpc.get_shared_groups_by_repo(repo_id)
    except SearpcError:
        group_ids = ''
    if not group_ids:
        return []

    groups = []
    for group_id in group_ids.split('\n'):
        if not group_id:
            continue
        group = get_group(group_id)
        if group:
            groups.append(group)
    return groups

def conv_repoids_to_list(repo_ids):
    """
    Convert repo ids seperated by "\n" to list.
    """
    if not repo_ids:
        return []

    repoid_list = []
    for repo_id in repo_ids.split("\n"):
        if repo_id == '':
            continue
        repoid_list.append(repo_id)
    return repoid_list
    
def get_group_repoids(group_id):
    """Get repo ids of a given group id."""
    try:
        repo_ids = seafserv_threaded_rpc.get_group_repoids(group_id)
    except SearpcError:
        return []

    return conv_repoids_to_list(repo_ids)

def get_group_repos(group_id, user):
    """Get repos of a given group id."""
    repoid_list = get_group_repoids(group_id)

    repos = []
    for repo_id in repoid_list:
        if not repo_id:
            continue
        repo = get_repo(repo_id)
        if not repo:
            continue

        repo.owner = seafserv_threaded_rpc.get_group_repo_owner(repo_id)
        repo.share_from_me = True if user == repo.owner else False

        last_commit = get_commits(repo.id, 0, 1)[0]
        repo.latest_modify = last_commit.ctime if last_commit else None

        repos.append(repo)
    repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify))
    
    return repos

# org group repo
def del_org_group_repo(repo_id, org_id, group_id):
    seafserv_threaded_rpc.del_org_group_repo(repo_id, org_id, group_id)

def get_org_group_repoids(org_id, group_id):
    try:
        repo_ids = seafserv_threaded_rpc.get_org_group_repoids(org_id, group_id)
    except SearpcError:
        repo_ids = ''

    return conv_repoids_to_list(repo_ids)

def get_org_group_repos(org_id, group_id, user):
    """Get org repos of a given group id."""
    repoid_list = get_org_group_repoids(org_id, group_id)
    if not repoid_list:
        return []
    
    repos = []
    for repo_id in repoid_list:
        if not repo_id:
            continue
        repo = get_repo(repo_id)
        if not repo:
            continue

        repo.owner = seafserv_threaded_rpc.get_org_group_repo_owner(org_id,
                                                                    group_id,
                                                                    repo_id)
        repo.sharecd_from_me = True if user == repo.owner else False

        last_commit = get_commits(repo.id, 0, 1)[0]
        repo.latest_modify = last_commit.ctime if last_commit else None

        repos.append(repo)
    repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify))
    
    return repos

def get_org_groups_by_repo(org_id, repo_id):
    try:
        group_ids = seafserv_threaded_rpc.get_org_groups_by_repo(org_id,
                                                                 repo_id)
    except SearpcError:
        group_ids = ''
    if not group_ids:
        return []

    groups = []
    for group_id in group_ids.split('\n'):
        if not group_id:
            continue
        group = get_group(group_id)
        if group:
            groups.append(group)
    return groups
    
# inner pub repo
def list_inner_pub_repos_by_owner(user):
    """
    List a user's inner pub repos.
    """
    try:
        ret = seafserv_threaded_rpc.list_inner_pub_repos_by_owner(user)
    except SearpcError:
        ret = []
    return ret

def list_inner_pub_repos(username):
    """
    List inner pub repos, which can be access by everyone.
    """
    try:
        shared_repos = seafserv_threaded_rpc.list_inner_pub_repos()
    except:
        shared_repos = []

    for repo in shared_repos:
        repo.user_perm = check_permission(repo.props.repo_id, username)

    shared_repos.sort(lambda x, y: cmp(y.props.last_modified, x.props.last_modified))
    return shared_repos

def count_inner_pub_repos():
    try:
        ret = seafserv_threaded_rpc.count_inner_pub_repos()
    except SearpcError:
        ret = -1
    return 0 if ret < 0 else ret

def is_inner_pub_repo(repo_id):
    """
    Check whether a repo is public.
    Return 0 if repo is not inner public, otherwise non-zero.
    """
    try:
        ret = seafserv_threaded_rpc.is_inner_pub_repo(repo_id)
    except SearpcError:
        ret = 0

    return ret

def unset_inner_pub_repo(repo_id):
    seafserv_threaded_rpc.unset_inner_pub_repo(repo_id)
        
# org inner pub repo
def list_org_inner_pub_repos(org_id, username, start=None, limit=None):
    """
    List org inner pub repos, which can be access by all org members.
    """
    try:
        shared_repos = seafserv_threaded_rpc.list_org_inner_pub_repos(org_id)
    except SearpcError:
        shared_repos = []

    for repo in shared_repos:
        repo.user_perm = check_permission(repo.props.repo_id, username)

    # sort repos by last modify time
    shared_repos.sort(lambda x, y: cmp(y.props.last_modified, x.props.last_modified))
    return shared_repos

# repo permissoin
def check_permission(repo_id, user):
    """
    Check whether user has permission to access repo.
    Return values can be 'rw' or 'r' or None.
    """
    try:
        ret = seafserv_threaded_rpc.check_permission(repo_id, user)
    except SearpcError:
        ret = None
    return ret

def is_personal_repo(repo_id):
    """
    Check whether repo is personal repo.
    """
    try:
        owner = seafserv_threaded_rpc.get_repo_owner(repo_id)
    except SearpcError:
        owner = ''
    return True if owner else False

# shared repo
def list_share_repos(user, share_type, start, limit):
    try:
        ret = seafserv_threaded_rpc.list_share_repos(user, share_type,
                                                     start, limit)
    except SearpcError:
        ret = []
    return ret

def remove_share(repo_id, from_user, to_user):
    seafserv_threaded_rpc.remove_share(repo_id, from_user, to_user)

def unshare_group_repo(repo_id, group_id, from_user):
    return seafserv_threaded_rpc.group_unshare_repo(repo_id, int(group_id),
                                                    from_user)
        
def list_personal_shared_repos(user, user_type, start, limit):
    """
    List personal repos that user share with others.
    If `user_type` is 'from_email', list repos user shares to others;
    If `user_type` is 'to_email', list repos others share to user.
    """
    share_repos = list_share_repos(user, user_type, start, limit)
    for repo in share_repos:
        repo.user_perm = check_permission(repo.props.repo_id, user)

    share_repos.sort(lambda x, y: cmp(y.last_modified, x.last_modified))
    return share_repos

def list_org_shared_repos(org_id, user, user_type, start, limit):
    """
    List org repos that user share with others.
    If `user_type` is 'from_email', list repos user shares to others;
    If `user_type` is 'to_email', list repos others sahre to user.
    """
    try:
        share_repos = seafserv_threaded_rpc.list_org_share_repos(org_id,
                                                                 user, user_type,
                                                                 start, limit)
    except SearpcError:
        share_repos = []

    for repo in share_repos:
        repo.user_perm = check_permission(repo.props.repo_id, user)

    share_repos.sort(lambda x, y: cmp(y.last_modified, x.last_modified))
    return share_repos

# dir
def list_dir_by_path(repo_id, commit_id, path):
    try:
        ret = seafserv_threaded_rpc.list_dir_by_path(repo_id, commit_id, path)
    except SearpcError:
        ret = None
    return ret

# file
def post_empty_file(repo_id, parent_dir, file_name, user):
    """
    Return true if successfully make a new file, otherwise false.
    """
    try:
        ret = seafserv_threaded_rpc.post_empty_file(repo_id, parent_dir,
                                              file_name, user)
    except SearpcError, e:
        logger.error(e)
        ret = -1
    return True if ret == 0 else False

def del_file(repo_id, parent_dir, file_name, user):
    """
    Return true if successfully delete a file, otherwise false.
    """
    try:
        ret = seafserv_threaded_rpc.del_file(repo_id, parent_dir,
                                             file_name, user)
    except SearpcError, e:
        logger.error(e)
        ret = -1
    return True if ret == 0 else False

# misc functions
def is_valid_filename(file_or_dir):
    """
    Check whether file name or directory name is valid.
    """
    try:
        ret = seafserv_threaded_rpc.is_valid_filename('', file_or_dir)
    except SearpcError:
        ret = 0

    return ret

def get_file_size(store_id, version, file_id):
    try:
        fs = seafserv_threaded_rpc.get_file_size(store_id, version, file_id)
    except SearpcError, e:
        fs = 0
    return fs

def get_file_id_by_path(repo_id, path):
    try:
        ret = seafserv_threaded_rpc.get_file_id_by_path(repo_id, path)
    except SearpcError, e:
        ret = ''
    return ret

def get_related_users_by_repo(repo_id):
    """Give a repo id, returns a list of users of:
    - the repo owner
    - members of groups to which the repo is shared
    - users to which the repo is shared
    """
    owner = seafserv_threaded_rpc.get_repo_owner(repo_id)
    if not owner:
        # Can't happen
        return []

    users = [owner]

    groups = get_shared_groups_by_repo(repo_id)

    for group in groups:
        members = get_group_members(group.id)
        for member in members:
            if member.user_name not in users:
                users.append(member.user_name)

    share_repos = list_share_repos(owner, 'from_email', -1, -1)
    for repo in share_repos:
        if repo.repo_id == repo_id:
            if repo.user not in users:
                users.append(repo.user)

    return users

def get_related_users_by_org_repo(org_id, repo_id):
    """Org version of get_related_users_by_repo
    """
    owner = get_org_repo_owner(repo_id)

    if not owner:
        # Can't happen
        return []

    users = [owner]

    groups = get_org_groups_by_repo(org_id, repo_id)

    for group in groups:
        members = get_group_members(group.id)
        for member in members:
            if member.user_name not in users:
                users.append(member.user_name)

    share_repos = seafserv_threaded_rpc.list_org_share_repos(org_id, \
                                        owner, 'from_email', -1, -1)

    for repo in share_repos:
        if repo.repo_id == repo_id:
            if repo.user not in users:
                users.append(repo.user)

    return users

# quota
def check_quota(repo_id):
    try:
        ret = seafserv_threaded_rpc.check_quota(repo_id)
    except SearpcError, e:
        logger.error(e)
        ret = -1
    return ret

def get_user_quota(user):
    try:
        ret = seafserv_threaded_rpc.get_user_quota(user)
    except SearpcError, e:
        logger.error(e)
        ret = 0
    return ret

def get_user_quota_usage(user):
    try:
        ret = seafserv_threaded_rpc.get_user_quota_usage(user)
    except SearpcError, e:
        logger.error(e)
        ret = 0
    return ret

def get_user_share_usage(user):
    try:
        ret = seafserv_threaded_rpc.get_user_share_usage(user)
    except SearpcError, e:
        logger.error(e)
        ret = 0
    return ret
    
# access token
def web_get_access_token(repo_id, obj_id, op, username, use_onetime=1):
    try:
        ret = seafserv_rpc.web_get_access_token(repo_id, obj_id, op, username, use_onetime)
    except SearpcError, e:
        ret = ''
    return ret
    
# password management
def unset_repo_passwd(repo_id, user):
    """
    Remove user password of a encrypt repo.
    Arguments:
    - `repo_id`: encrypt repo id
    - `user`: username
    """
    try:
        ret = seafserv_threaded_rpc.unset_passwd(repo_id, user)
    except SearpcError, e:
        ret = -1
    return ret

def is_passwd_set(repo_id, user):
    try:
        ret = seafserv_rpc.is_passwd_set(repo_id, user)
    except SearpcError, e:
        ret = -1
    return True if ret == 1 else False

# repo history limit
def get_repo_history_limit(repo_id):
    try:
        ret = seafserv_threaded_rpc.get_repo_history_limit(repo_id)
    except SearpcError, e:
        ret = -1
    return ret

def set_repo_history_limit(repo_id, days):
    try:
        ret = seafserv_threaded_rpc.set_repo_history_limit(repo_id, days)
    except SearpcError, e:
        ret = -1
    return ret
