def test_share_repo_to_group(repo, group, permission): assert api.check_permission(repo.id, USER) == 'rw' assert api.check_permission(repo.id, USER2) is None repos = api.get_repos_by_group(group.id) assert len(repos) == 0 group_list = ccnet_api.get_groups(USER) assert len(group_list) == 1 group_list = ccnet_api.get_groups(USER2) assert len(group_list) == 0 api.group_share_repo(repo.id, group.id, USER, permission) repos = api.get_repos_by_group(group.id) assert_repo_with_permission(repo, repos, permission) ccnet_api.group_add_member(group.id, USER, USER2) group_list = ccnet_api.get_groups(USER2) assert len(group_list) == 1 group = group_list[0] assert group.id == group.id repos2 = api.get_repos_by_group(group.id) assert_repo_with_permission(repo, repos2, permission) assert api.check_permission(repo.id, USER2) == permission api.group_unshare_repo(repo.id, group.id, USER) repos = api.get_repos_by_group(group.id) assert len(repos) == 0 assert api.check_permission(repo.id, USER2) is None
def get(self, request, email): """ return all groups user joined Permission checking: 1. Admin user; """ if not request.user.admin_permissions.can_manage_user(): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') try: User.objects.get(email=email) except User.DoesNotExist as e: logger.error(e) error_msg = 'User %s not found.' % email return api_error(status.HTTP_404_NOT_FOUND, error_msg) groups_info = [] try: groups = ccnet_api.get_groups(email) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) # Use dict to reduce memcache fetch cost in large for-loop. nickname_dict = {} creator_name_set = set([g.creator_name for g in groups]) for e in creator_name_set: if e not in nickname_dict: nickname_dict[e] = email2nickname(e) for group in groups: isoformat_timestr = timestamp_to_isoformat_timestr(group.timestamp) group_info = { "id": group.id, "name": group.group_name, "owner_email": group.creator_name, "owner_name": nickname_dict.get(group.creator_name, ''), "created_at": isoformat_timestr, "parent_group_id": group.parent_group_id if is_pro_version() else 0 } groups_info.append(group_info) try: is_group_staff = ccnet_api.check_group_staff(group.id, email) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if email == group.creator_name: group_info['role'] = 'Owner' elif is_group_staff: group_info['role'] = 'Admin' else: group_info['role'] = 'Member' return Response({'group_list': groups_info})
def check_dtable_permission(username, workspace, dtable=None, org_id=None): """Check workspace/dtable access permission of a user. """ owner = workspace.owner if '@seafile_group' in owner: group_id = int(owner.split('@')[0]) if is_group_member(group_id, username): return PERMISSION_READ_WRITE else: if username == owner: return PERMISSION_READ_WRITE if dtable: # check user's all permissions from `share`, `group-share` and checkout higher one dtable_share = DTableShare.objects.get_by_dtable_and_to_user( dtable, username) if dtable_share and dtable_share.permission == PERMISSION_READ_WRITE: return dtable_share.permission permission = dtable_share.permission if dtable_share else None if org_id and org_id > 0: groups = ccnet_api.get_org_groups_by_user(org_id, username) else: groups = ccnet_api.get_groups(username, return_ancestors=True) group_ids = [group.id for group in groups] group_permissions = DTableGroupShare.objects.filter( dtable=dtable, group_id__in=group_ids).values_list('permission', flat=True) for group_permission in group_permissions: permission = permission if permission else group_permission if group_permission == PERMISSION_READ_WRITE: return group_permission return permission return None
def rename_group_with_new_name(request, group_id, new_group_name): """Rename a group with new name. Arguments: - `request`: - `group_id`: - `new_group_name`: Raises: BadGroupNameError: New group name format is not valid. ConflictGroupNameError: New group name confilicts with existing name. """ if not validate_group_name(new_group_name): raise BadGroupNameError # Check whether group name is duplicated. username = request.user.username org_id = -1 if is_org_context(request): org_id = request.user.org.org_id checked_groups = seaserv.get_org_groups_by_user(org_id, username) else: if request.cloud_mode: checked_groups = ccnet_api.get_groups(username) else: checked_groups = get_all_groups(-1, -1) for g in checked_groups: if g.group_name == new_group_name: raise ConflictGroupNameError ccnet_threaded_rpc.set_group_name(group_id, new_group_name)
def get(self, request): """ List groups that user can share a library to. """ if config.ENABLE_SHARE_TO_ALL_GROUPS: if CUSTOM_GET_GROUPS: groups = custom_get_groups(request) else: groups = ccnet_api.get_all_groups(-1, -1) else: username = request.user.username if is_org_context(request): org_id = request.user.org.org_id groups = ccnet_api.get_org_groups_by_user(org_id, username) else: groups = ccnet_api.get_groups(username) try: avatar_size = int(request.GET.get('avatar_size', GROUP_AVATAR_DEFAULT_SIZE)) except ValueError: avatar_size = GROUP_AVATAR_DEFAULT_SIZE result = [self._get_group_info(request, group, avatar_size) for group in groups] return Response(result)
def get(self, request): user = request.user org_id = -1 if is_org_context(request): org_id = request.user.org.org_id if org_id and org_id > 0: groups = ccnet_api.get_org_groups_by_user(org_id, user.username) else: groups = ccnet_api.get_groups(user.username, return_ancestors=True) starred_dtable_uuids = set( UserStarredDTables.objects.get_dtable_uuids_by_email( user.username)) group_ids = [group.id for group in groups] dgses = DTableGroupShare.objects.filter( group_id__in=group_ids, dtable__deleted=False).order_by( 'created_at').select_related('dtable') results = { group_id: [] for group_id in dgses.values_list('group_id', flat=True) } for dgs in dgses: dtable_info = dgs.dtable.to_dict() dtable_info[ 'starred'] = dgs.dtable.uuid.hex in starred_dtable_uuids results[dgs.group_id].append(dtable_info) return Response({'group_shared_dtables': results})
def get(self, request): """ List groups that user can share a library to. """ if config.ENABLE_SHARE_TO_ALL_GROUPS: if CUSTOM_GET_GROUPS: groups = custom_get_groups(request) else: groups = ccnet_api.get_all_groups(-1, -1) else: username = request.user.username if is_org_context(request): org_id = request.user.org.org_id groups = ccnet_api.get_org_groups_by_user(org_id, username) else: groups = ccnet_api.get_groups(username) filtered_groups = [] for group in groups: if not ENABLE_SHARE_TO_DEPARTMENT and group.parent_group_id != 0: continue else: filtered_groups.append(group) result = [ self._get_group_info(request, group) for group in filtered_groups ] return Response(result)
def get(self, request): """ List groups that user can share a library to. """ if config.ENABLE_SHARE_TO_ALL_GROUPS: if CUSTOM_GET_GROUPS: groups = custom_get_groups(request) else: groups = ccnet_api.get_all_groups(-1, -1) else: username = request.user.username if is_org_context(request): org_id = request.user.org.org_id groups = ccnet_api.get_org_groups_by_user(org_id, username) else: groups = ccnet_api.get_groups(username) try: avatar_size = int( request.GET.get('avatar_size', GROUP_AVATAR_DEFAULT_SIZE)) except ValueError: avatar_size = GROUP_AVATAR_DEFAULT_SIZE result = [ self._get_group_info(request, group, avatar_size) for group in groups ] return Response(result)
def remove_user(self, email=None): if not email: email = self.user.username try: User.objects.get(email).delete() except User.DoesNotExist: pass for g in ccnet_api.get_groups(email): ccnet_threaded_rpc.remove_group(g.id, email)
def user_info(request, email): """Show user info, libraries and groups. """ owned_repos = mute_seafile_api.get_owned_repo_list(email, ret_corrupted=True) owned_repos = [r for r in owned_repos if not r.is_virtual] in_repos = mute_seafile_api.get_share_in_repo_list(email, -1, -1) space_usage = mute_seafile_api.get_user_self_usage(email) space_quota = mute_seafile_api.get_user_quota(email) # get user profile profile = Profile.objects.get_profile_by_user(email) d_profile = DetailedProfile.objects.get_detailed_profile_by_user(email) try: personal_groups = ccnet_api.get_groups(email) except SearpcError as e: logger.error(e) personal_groups = [] for g in personal_groups: try: is_group_staff = seaserv.check_group_staff(g.id, email) except SearpcError as e: logger.error(e) is_group_staff = False if email == g.creator_name: g.role = _('Owner') elif is_group_staff: g.role = _('Admin') else: g.role = _('Member') available_quota = get_institution_available_quota(request.user.institution) return render( request, 'institutions/user_info.html', { 'owned_repos': owned_repos, 'space_quota': space_quota, 'space_usage': space_usage, 'in_repos': in_repos, 'email': email, 'profile': profile, 'd_profile': d_profile, 'personal_groups': personal_groups, 'available_quota': available_quota, })
def check_dtable_permission(self): """Check workspace/dtable access permission of a user. """ owner = self.workspace_owner username = self.username if not hasattr(self, 'org_id'): self.org_id = -1 org_id = self.org_id if '@seafile_group' in owner: group_id = int(owner.split('@')[0]) if self.is_group_member(group_id, username): return PERMISSION_READ_WRITE else: if username == owner: return PERMISSION_READ_WRITE self.dtable = self.db_session.query(DTables).filter_by( uuid=self.dtable_uuid).first() dtable = self.dtable if dtable: # check user's all permissions from `share`, `group-share` and checkout higher one dtable_share = self.db_session.query(DTableShare).filter_by( dtable_id=dtable.id, to_user=username).first() if dtable_share and dtable_share.permission == PERMISSION_READ_WRITE: return dtable_share.permission permission = dtable_share.permission if dtable_share else '' if org_id and org_id > 0: groups = ccnet_api.get_org_groups_by_user(org_id, username) else: groups = ccnet_api.get_groups(username, return_ancestors=True) group_ids = [group.id for group in groups] group_permissions = self.db_session.query( DTableGroupShare.permission).filter( DTableGroupShare.dtable_id == dtable.id, DTableGroupShare.group_id.in_(group_ids)).all() for group_permission in group_permissions: permission = permission if permission else group_permission[0] if group_permission[0] == PERMISSION_READ_WRITE: return group_permission[0] return permission return ''
def get(self, request): """get shared forms """ username = request.user.username org_id = -1 if is_org_context(request): org_id = request.user.org.org_id if org_id and org_id > 0: groups = ccnet_api.get_org_groups_by_user(org_id, username) else: groups = ccnet_api.get_groups(username, return_ancestors=True) group_ids = [group.id for group in groups] group_name_map = { group_id: group_id_to_name(group_id) for group_id in group_ids } try: shared_queryset = DTableFormShare.objects.list_by_group_ids( group_ids) except Exception as e: logger.error(e) error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) shared_list = list() for item in shared_queryset: form = item.form if form.share_type != SHARED_GROUPS: continue data = form.to_dict() group_id = item.group_id data["group_name"] = group_name_map.get(group_id) data["group_id"] = group_id shared_list.append(data) return Response({'shared_list': shared_list}, status=status.HTTP_200_OK)
def post(self, request, email, format=None): # migrate an account's repos and groups to an exist account if not is_valid_username(email): return api_error(status.HTTP_400_BAD_REQUEST, 'Email %s invalid.' % email) op = request.data.get('op', '').lower() if op == 'migrate': from_user = email to_user = request.data.get('to_user', '') if not is_valid_username(to_user): return api_error(status.HTTP_400_BAD_REQUEST, 'Email %s invalid.' % to_user) try: user2 = User.objects.get(email=to_user) except User.DoesNotExist: return api_error(status.HTTP_404_NOT_FOUND, 'User %s not found.' % to_user) # transfer owned repos to new user for r in seafile_api.get_owned_repo_list(from_user): seafile_api.set_repo_owner(r.id, user2.username) # transfer shared repos to new user for r in seafile_api.get_share_in_repo_list(from_user, -1, -1): owner = seafile_api.get_repo_owner(r.repo_id) seafile_api.share_repo(r.repo_id, owner, to_user, r.permission) # transfer joined groups to new user for g in ccnet_api.get_groups(from_user): if not is_group_member(g.id, user2.username): # add new user to the group on behalf of the group creator ccnet_threaded_rpc.group_add_member( g.id, g.creator_name, to_user) if from_user == g.creator_name: ccnet_threaded_rpc.set_group_creator(g.id, to_user) return Response({'success': True}) else: return api_error(status.HTTP_400_BAD_REQUEST, 'op can only be migrate.')
def get(self, request, format=None): """ Search group. Permission checking: 1. default(NOT guest) user; """ # argument check q = request.GET.get('q', None) if not q: error_msg = 'q invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # permission check if not self._can_use_global_address_book(request): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if CLOUD_MODE: if is_org_context(request): org_id = request.user.org.org_id groups = ccnet_api.get_org_groups(org_id, -1, -1) elif settings.ENABLE_GLOBAL_ADDRESSBOOK: groups = ccnet_api.get_all_groups(-1, -1) else: username = request.user.username groups = ccnet_api.get_groups(username) else: groups = ccnet_api.get_all_groups(-1, -1) result = [] for group in groups: group_name = group.group_name if not group_name: continue if q.lower() in group_name.lower(): group_info = get_group_info(group.id) result.append(group_info) return Response(result)
def get_groups(email): group_json = [] joined_groups = ccnet_api.get_groups(email) grpmsgs = {} for g in joined_groups: grpmsgs[g.id] = 0 replynum = 0 for g in joined_groups: group = { "id": g.id, "name": g.group_name, "creator": g.creator_name, "ctime": g.timestamp, "msgnum": grpmsgs[g.id], } group_json.append(group) return group_json, replynum
def check_group_name_conflict(request, new_group_name): """Check if new group name conflict with existed group. return "True" if conflicted else "False" """ org_id = -1 username = request.user.username if is_org_context(request): org_id = request.user.org.org_id checked_groups = seaserv.get_org_groups_by_user(org_id, username) else: if request.cloud_mode: checked_groups = ccnet_api.get_groups(username) else: checked_groups = ccnet_api.search_groups(new_group_name, -1, -1) for g in checked_groups: if g.group_name == new_group_name: return True return False
def get(self, request): """ List all groups. """ org_id = None username = request.user.username if is_org_context(request): org_id = request.user.org.org_id user_groups = seaserv.get_org_groups_by_user(org_id, username) else: user_groups = ccnet_api.get_groups(username, return_ancestors=True) try: avatar_size = int( request.GET.get('avatar_size', GROUP_AVATAR_DEFAULT_SIZE)) except ValueError: avatar_size = GROUP_AVATAR_DEFAULT_SIZE groups = [] for g in user_groups: group_info = get_group_info(request, g.id, avatar_size) groups.append(group_info) return Response(groups)
def check_form_submit_permission(request, form): share_type = form.share_type is_auth = request.user.is_authenticated() username = request.user.username if is_auth and username == form.username: return True if share_type == ANONYMOUS: return True elif share_type == LOGIN_USERS and is_auth: return True elif share_type == SHARED_GROUPS and is_auth: user_groups = ccnet_api.get_groups(request.user.username) user_group_ids = [group.id for group in user_groups] shared_group_ids = DTableFormShare.objects.list_by_form(form) intersection = [ group_id for group_id in user_group_ids if group_id in shared_group_ids ] if intersection: return True return False
def get(self, request): """get all workspaces """ username = request.user.username org_id = -1 if is_org_context(request): org_id = request.user.org.org_id if org_id > 0: groups = ccnet_api.get_org_groups_by_user(org_id, username) else: groups = ccnet_api.get_groups(username, return_ancestors=True) owner_list = list() owner_list.append(username) for group in groups: group_user = '******' % group.id owner_list.append(group_user) workspace_list = list() for owner in owner_list: try: workspace = Workspaces.objects.get_workspace_by_owner(owner) except Exception as e: logger.error(e) error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if not workspace: if '@seafile_group' in owner: continue # permission check if not request.user.permissions.can_add_repo(): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) try: if org_id > 0: repo_id = seafile_api.create_org_repo( _("My Workspace"), _("My Workspace"), "dtable@seafile", org_id) else: repo_id = seafile_api.create_repo( _("My Workspace"), _("My Workspace"), "dtable@seafile") except Exception as e: logger.error(e) error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) workspace = Workspaces.objects.create_workspace(owner, repo_id) # resource check repo_id = workspace.repo_id repo = seafile_api.get_repo(repo_id) if not repo: logger.warning('Library %s not found.' % repo_id) continue res = workspace.to_dict() table_list = DTables.objects.get_dtable_by_workspace(workspace) res["table_list"] = table_list if '@seafile_group' in owner: group_id = owner.split('@')[0] res["owner_name"] = group_id_to_name(group_id) res["owner_type"] = "Group" else: res["owner_name"] = email2nickname(owner) res["owner_type"] = "Personal" workspace_list.append(res) return Response({"workspace_list": workspace_list}, status=status.HTTP_200_OK)
def get(self, request): """ List all groups. """ org_id = None username = request.user.username if is_org_context(request): org_id = request.user.org.org_id user_groups = seaserv.get_org_groups_by_user(org_id, username) else: user_groups = ccnet_api.get_groups(username, return_ancestors=True) try: avatar_size = int(request.GET.get('avatar_size', GROUP_AVATAR_DEFAULT_SIZE)) except ValueError: avatar_size = GROUP_AVATAR_DEFAULT_SIZE try: with_repos = int(request.GET.get('with_repos', 0)) except ValueError: with_repos = 0 if with_repos not in (0, 1): error_msg = 'with_repos invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) groups = [] if with_repos: gids = [g.id for g in user_groups] admin_info = ExtraGroupsSharePermission.objects.batch_get_repos_with_admin_permission(gids) try: starred_repos = UserStarredFiles.objects.get_starred_repos_by_user(username) starred_repo_id_list = [item.repo_id for item in starred_repos] except Exception as e: logger.error(e) starred_repo_id_list = [] for g in user_groups: group_info = get_group_info(request, g.id, avatar_size) if with_repos: if org_id: group_repos = seafile_api.get_org_group_repos(org_id, g.id) else: group_repos = seafile_api.get_repos_by_group(g.id) repos = [] # get repo id owner dict all_repo_owner = [] repo_id_owner_dict = {} for repo in group_repos: repo_id = repo.id if repo_id not in repo_id_owner_dict: repo_owner = get_repo_owner(request, repo_id) all_repo_owner.append(repo_owner) repo_id_owner_dict[repo_id] = repo_owner # Use dict to reduce memcache fetch cost in large for-loop. name_dict = {} contact_email_dict = {} for email in all_repo_owner: if email not in name_dict: if '@seafile_group' in email: group_id = get_group_id_by_repo_owner(email) group_name= group_id_to_name(group_id) name_dict[email] = group_name else: name_dict[email] = email2nickname(email) if email not in contact_email_dict: if '@seafile_group' in email: contact_email_dict[email] = '' else: contact_email_dict[email] = email2contact_email(email) for r in group_repos: repo_owner = repo_id_owner_dict.get(r.id, r.user) repo = { "id": r.id, "repo_id": r.id, "name": r.name, "repo_name": r.name, "size": r.size, "size_formatted": filesizeformat(r.size), "mtime": r.last_modified, "mtime_relative": translate_seahub_time(r.last_modified), "last_modified": timestamp_to_isoformat_timestr(r.last_modified), "encrypted": r.encrypted, "permission": r.permission, "owner": repo_owner, "owner_email": repo_owner, "owner_name": name_dict.get(repo_owner, ''), "owner_contact_email": contact_email_dict.get(repo_owner, ''), "is_admin": (r.id, g.id) in admin_info, "starred": r.repo_id in starred_repo_id_list, } repos.append(repo) group_info['repos'] = repos groups.append(group_info) return Response(groups)
def get(self, request): """ List all groups. """ org_id = None username = request.user.username if is_org_context(request): org_id = request.user.org.org_id user_groups = seaserv.get_org_groups_by_user(org_id, username) else: user_groups = ccnet_api.get_groups(username, return_ancestors=True) try: avatar_size = int( request.GET.get('avatar_size', GROUP_AVATAR_DEFAULT_SIZE)) except ValueError: avatar_size = GROUP_AVATAR_DEFAULT_SIZE try: with_repos = int(request.GET.get('with_repos', 0)) except ValueError: with_repos = 0 if with_repos not in (0, 1): error_msg = 'with_repos invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) groups = [] if with_repos: gids = [g.id for g in user_groups] admin_info = ExtraGroupsSharePermission.objects.batch_get_repos_with_admin_permission( gids) for g in user_groups: group_info = get_group_info(request, g.id, avatar_size) if with_repos: if org_id: group_repos = seafile_api.get_org_group_repos(org_id, g.id) else: group_repos = seafile_api.get_repos_by_group(g.id) repos = [] for r in group_repos: repo = { "id": r.id, "name": r.name, "size": r.size, "size_formatted": filesizeformat(r.size), "mtime": r.last_modified, "mtime_relative": translate_seahub_time(r.last_modified), "encrypted": r.encrypted, "permission": r.permission, "owner": r.user, "owner_name": email2nickname(r.user), "is_admin": (r.id, g.id) in admin_info } repos.append(repo) group_info['repos'] = repos groups.append(group_info) return Response(groups)
def libraries(request): """ New URL to replace myhome """ username = request.user.username # options if request.cloud_mode and request.user.org is None: allow_public_share = False else: allow_public_share = True sub_lib_enabled = UserOptions.objects.is_sub_lib_enabled(username) max_upload_file_size = get_max_upload_file_size() guide_enabled = UserOptions.objects.is_user_guide_enabled(username) if guide_enabled: create_default_library(request) folder_perm_enabled = True if is_pro_version( ) and ENABLE_FOLDER_PERM else False can_add_pub_repo = True if is_org_repo_creation_allowed(request) else False if request.cloud_mode and request.user.org is not None: org_id = request.user.org.org_id joined_groups = seaserv.get_org_groups_by_user(org_id, username) else: joined_groups = ccnet_api.get_groups(username, return_ancestors=True) if joined_groups: try: joined_groups.sort( lambda x, y: cmp(x.group_name.lower(), y.group_name.lower())) except Exception as e: logger.error(e) joined_groups = [] joined_groups_exclude_address_book = [ item for item in joined_groups if item.parent_group_id == 0 ] return render(request, 'libraries.html', { "allow_public_share": allow_public_share, "guide_enabled": guide_enabled, "sub_lib_enabled": sub_lib_enabled, 'enable_wiki': settings.ENABLE_WIKI, 'enable_upload_folder': settings.ENABLE_UPLOAD_FOLDER, 'enable_resumable_fileupload': settings.ENABLE_RESUMABLE_FILEUPLOAD, 'max_number_of_files_for_fileupload': settings.MAX_NUMBER_OF_FILES_FOR_FILEUPLOAD, 'enable_thumbnail': settings.ENABLE_THUMBNAIL, 'enable_repo_snapshot_label': settings.ENABLE_REPO_SNAPSHOT_LABEL, 'thumbnail_default_size': settings.THUMBNAIL_DEFAULT_SIZE, 'thumbnail_size_for_grid': settings.THUMBNAIL_SIZE_FOR_GRID, 'enable_encrypted_library': config.ENABLE_ENCRYPTED_LIBRARY, 'enable_repo_history_setting': config.ENABLE_REPO_HISTORY_SETTING, 'max_upload_file_size': max_upload_file_size, 'folder_perm_enabled': folder_perm_enabled, 'is_pro': True if is_pro_version() else False, 'file_audit_enabled': FILE_AUDIT_ENABLED, 'can_add_pub_repo': can_add_pub_repo, 'joined_groups': joined_groups, 'joined_groups_exclude_address_book': joined_groups_exclude_address_book, 'storages': get_library_storages(request), 'unread_notifications_request_interval': UNREAD_NOTIFICATIONS_REQUEST_INTERVAL, 'library_templates': LIBRARY_TEMPLATES.keys() if \ isinstance(LIBRARY_TEMPLATES, dict) else [], 'enable_share_to_all_groups': config.ENABLE_SHARE_TO_ALL_GROUPS, 'enable_group_discussion': settings.ENABLE_GROUP_DISCUSSION, 'enable_file_comment': settings.ENABLE_FILE_COMMENT, })
def do_action(self): emails = [] user_dtable_updates_email_intervals = [] for ele in UserOptions.objects.filter( option_key=KEY_DTABLE_UPDATES_EMAIL_INTERVAL): try: user_dtable_updates_email_intervals.append( (ele.email, int(ele.option_val))) emails.append(ele.email) except Exception as e: logger.error(e) self.stderr.write('[%s]: %s' % (str(datetime.now()), e)) continue user_last_emailed_time_dict = {} for ele in UserOptions.objects.filter( option_key=KEY_DTABLE_UPDATES_LAST_EMAILED_TIME).filter( email__in=emails): try: user_last_emailed_time_dict[ele.email] = datetime.strptime( ele.option_val, "%Y-%m-%d %H:%M:%S") except Exception as e: logger.error(e) self.stderr.write('[%s]: %s' % (str(datetime.now()), e)) continue for (username, interval_val) in user_dtable_updates_email_intervals: # save current language cur_language = translation.get_language() # get and active user language user_language = self.get_user_language(username) translation.activate(user_language) logger.debug('Set language code to %s for user: %s' % (user_language, username)) self.stdout.write('[%s] Set language code to %s for user: %s' % (str(datetime.now()), user_language, username)) # get last_emailed_time if any, defaults to today 00:00:00.0 last_emailed_time = user_last_emailed_time_dict.get(username, None) now = datetime.utcnow().replace(microsecond=0) if not last_emailed_time: last_emailed_time = datetime.utcnow().replace(hour=0).replace( minute=0).replace(second=0).replace(microsecond=0) else: if (now - last_emailed_time).total_seconds() < interval_val: continue # find all the user's tables and groups' tables groups = ccnet_api.get_groups(username, return_ancestors=True) owner_list = [username] + [ '%s@seafile_group' % group.id for group in groups ] dtables = list( DTables.objects.filter(workspace__owner__in=owner_list)) # find all tables shared to user shared_tables = list(DTableShare.objects.list_by_to_user(username)) # combine tables dtables.extend([item.dtable for item in shared_tables]) # dtable uuid map dtables_uuid_map = {dtable.uuid.hex: dtable for dtable in dtables} # query all activities about above dtables with DB SQL cursor = connection.cursor() sql = "SELECT a.* FROM activities a JOIN user_activities ua ON a.id=ua.activity_id WHERE ua.timestamp > %s AND ua.username=%s ORDER BY ua.timestamp DESC" cursor.execute(sql, (last_emailed_time, username)) # time and username col_names = [desc[0] for desc in cursor.description] activities, activities_count = [], 0 for activity in cursor.fetchall(): activity = dict(zip(col_names, activity)) if activity['dtable_uuid'] not in dtables_uuid_map: continue activity_detail = json.loads(activity['detail']) activity_dict = dict(dtable_uuid=activity['dtable_uuid']) activity_dict['dtable_name'] = dtables_uuid_map[ activity['dtable_uuid']].name if activity[ 'dtable_uuid'] in dtables_uuid_map else '' activity_dict['row_id'] = activity['row_id'] activity_dict['op_type'] = activity['op_type'] activity_dict['author_email'] = activity['op_user'] activity_dict['author_name'] = email2nickname( activity['op_user']) activity_dict['author_contact_email'] = email2contact_email( activity['op_user']) activity_dict['op_time'] = utc_datetime_to_isoformat_timestr( activity['op_time']) activity_dict['table_id'] = activity_detail['table_id'] activity_dict['table_name'] = activity_detail['table_name'] activity_dict['row_data'] = activity_detail['row_data'] activity_dict['row_name'] = self.get_row_name( activity_dict['row_data']) or activity_detail.get( 'row_name', '') # compatible with previous data avatar_size = 72 # todo: size url, is_default, date_uploaded = api_avatar_url( activity['op_user'], avatar_size) activity_dict['avatar_url'] = url # fields for html-display activity_dict['op_user_link'] = a_tag( activity_dict['author_name'], user_info_url(activity['op_user'])) activity_dict['dtable_link'] = a_tag( activity_dict['dtable_name'], dtable_url(dtables_uuid_map[activity_dict['dtable_uuid']])) activity_dict['details'] = self.format_modify_operation( activity_dict) activity_dict['local_timestamp'] = utc_to_local( activity['op_time']) activities_count += 1 if len(activities) <= 100: activities.append(activity_dict) if not activities: translation.activate(cur_language) continue c = { 'name': email2nickname(username), 'updates_count': activities_count, 'updates': activities, } contact_email = email2contact_email(username) try: send_html_email( _('New table updates on %s') % get_site_name(), 'notifications/dtable_updates_email.html', c, None, [contact_email]) now = datetime.utcnow().replace(microsecond=0) UserOptions.objects.set_dtable_updates_last_emailed_time( username, now) except Exception as e: logger.error('Failed to send email to %s, error detail: %s' % (contact_email, e)) self.stderr.write('[%s] Failed to send email to %s, error ' 'detail: %s' % (str(datetime.now()), contact_email, e)) finally: # reset lang translation.activate(cur_language)
def test_multi_tier_groups(repo): id1 = ccnet_api.create_group('group1', USER, parent_group_id=-1) id2 = ccnet_api.create_group('group2', USER2, parent_group_id = id1) id3 = ccnet_api.create_group('group3', USER, parent_group_id = id1) id4 = ccnet_api.create_group('group4', USER2, parent_group_id = id3) id5 = ccnet_api.create_group('group5', USER2, parent_group_id = 0) assert id1 != -1 and id2 != -1 and id3 != -1 and id4 != -1 group1 = ccnet_api.get_group(id1) group2 = ccnet_api.get_group(id2) group3 = ccnet_api.get_group(id3) group4 = ccnet_api.get_group(id4) assert group1.parent_group_id == -1 assert group2.parent_group_id == id1 assert group3.parent_group_id == id1 assert group4.parent_group_id == id3 members = ccnet_api.search_group_members (id1, 'randgroup{}'.format(randstring(6))) assert len(members) == 0 members = ccnet_api.search_group_members (id1, USER) assert len(members) == 1 assert members[0].user_name == USER ances_order = [id5, id4, id3, id2, id1] user2_groups_with_ancestors = ccnet_api.get_groups (USER2, return_ancestors = True) assert len(user2_groups_with_ancestors) == 5 i = 0 for g in user2_groups_with_ancestors: assert g.id == ances_order[i] i = i + 1 order = [id5, id4, id2] i = 0 user2_groups = ccnet_api.get_groups (USER2) assert len(user2_groups) == 3 for g in user2_groups: assert g.id == order[i] i = i + 1 top_groups = ccnet_api.get_top_groups(True) assert len(top_groups) == 1 for g in top_groups: assert g.parent_group_id == -1 child_order = [id2, id3] i = 0 id1_children = ccnet_api.get_child_groups(id1) assert len(id1_children) == 2 for g in id1_children: assert g.id == child_order[i] i = i + 1 group4_order = [id1, id3, id4] i = 0 group4_ancestors = ccnet_api.get_ancestor_groups(id4) assert len(group4_ancestors) == 3 for g in group4_ancestors: assert g.id == group4_order[i] i = i + 1 rm5 = ccnet_api.remove_group(id5) rm4 = ccnet_api.remove_group(id4) rm3 = ccnet_api.remove_group(id3) rm2 = ccnet_api.remove_group(id2) rm1 = ccnet_api.remove_group(id1) assert rm5 == 0 and rm4 == 0 and rm3 == 0 and rm2 == 0 and rm1 == 0
def get(self, request): """get dtable forms Permission: 1. owner 2. group member 3. shared user with `rw` """ username = request.user.username # argument check workspace_id = request.GET.get('workspace_id') table_name = request.GET.get('name') # get user forms if not workspace_id and not table_name: org_id = -1 if is_org_context(request): org_id = request.user.org.org_id if org_id and org_id > 0: groups = ccnet_api.get_org_groups_by_user(org_id, username) else: groups = ccnet_api.get_groups(username, return_ancestors=True) owner_list = list() owner_list.append(username) for group in groups: group_user = '******' % group.id owner_list.append(group_user) try: # workspaces workspace_queryset = Workspaces.objects.filter( owner__in=owner_list) workspace_ids = [ workspace.id for workspace in workspace_queryset ] form_queryset = DTableForms.objects.filter( workspace_id__in=workspace_ids) except Exception as e: logger.error(e) error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) # forms group_name_map = { group.id: group_id_to_name(group.id) for group in groups } form_list = list() for form in form_queryset: data = form.to_dict() workspace_id = form.workspace_id workspace = workspace_queryset.get(id=workspace_id) owner = workspace.owner if '@seafile_group' in owner: group_id = int(owner.split('@')[0]) data["group_name"] = group_name_map.get(group_id) data["group_id"] = group_id form_list.append(data) return Response({"form_list": form_list}, status=status.HTTP_200_OK) # get dtable forms else: if not workspace_id: error_msg = 'workspace_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if not table_name: error_msg = 'name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # resource check workspace, dtable, error_msg = _resource_check( workspace_id, table_name) if error_msg: return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check if check_dtable_permission(username, workspace, dtable) != PERMISSION_READ_WRITE: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) dtable_uuid = dtable.uuid.hex try: forms = DTableForms.objects.get_forms_by_dtable_uuid( dtable_uuid) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) form_list = [form_obj.to_dict() for form_obj in forms] return Response({"form_list": form_list}, status=status.HTTP_200_OK)
def get(self, request): """get all workspaces """ username = request.user.username org_id = -1 if is_org_context(request): org_id = request.user.org.org_id if org_id and org_id > 0: groups = ccnet_api.get_org_groups_by_user(org_id, username) else: groups = ccnet_api.get_groups(username, return_ancestors=True) owner_list = list() owner_list.append(username) for group in groups: group_user = '******' % group.id owner_list.append(group_user) try: # workspaces workspace_queryset = Workspaces.objects.filter( owner__in=owner_list) workspaces = list(workspace_queryset) # user workspace if not workspace_queryset.filter(owner=username).exists(): workspace = create_repo_and_workspace(username, org_id) workspaces.append(workspace) # dtables table_queryset = DTables.objects.filter(workspace__in=workspaces, deleted=False) except Exception as e: logger.error(e) error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) try: starred_dtable_uuids = set( UserStarredDTables.objects.get_dtable_uuids_by_email(username)) except Exception as e: starred_dtable_uuids = set() logger.warning(e) workspace_list = list() for workspace in workspaces: # resource check repo_id = workspace.repo_id repo = seafile_api.get_repo(repo_id) if not repo: logger.warning('Library %s not found.' % repo_id) continue res = workspace.to_dict() tables = table_queryset.filter(workspace=workspace) res["table_list"] = [table.to_dict() for table in tables] for t in res['table_list']: t['starred'] = t['uuid'].hex in starred_dtable_uuids owner = workspace.owner if '@seafile_group' in owner: group_id = owner.split('@')[0] group_members = ccnet_api.get_group_members(int(group_id)) group_admins = [ m.user_name for m in group_members if m.is_staff ] group_owner = [ g.creator_name for g in groups if g.id == int(group_id) ][0] res["owner_name"] = group_id_to_name(group_id) res["owner_type"] = "Group" res["group_id"] = group_id res["group_owner"] = group_owner res["group_admins"] = group_admins else: res["owner_name"] = email2nickname(owner) res["owner_type"] = "Personal" workspace_list.append(res) if DTABLE_EVENTS_ENABLED: timestamp = datetime.utcnow().strftime('%Y-%m-%d 00:00:00') message = { 'username': username, 'timestamp': timestamp, 'org_id': org_id } try: events_redis_connection.publish('user-activity-statistic', json.dumps(message)) except Exception as e: logger.error("Failed to publish message: %s " % e) return Response({"workspace_list": workspace_list}, status=status.HTTP_200_OK)
def test_share_repo_to_group(repo, group, permission): assert api.check_permission(repo.id, USER) == 'rw' assert api.check_permission(repo.id, USER2) is None repos = api.get_repos_by_group(group.id) assert len(repos) == 0 group_list = ccnet_api.get_groups(USER) assert len(group_list) == 1 group_list = ccnet_api.get_groups(USER2) assert len(group_list) == 0 api.group_share_repo(repo.id, group.id, USER, permission) repos = api.get_repos_by_group(group.id) assert_repo_with_permission(repo, repos, permission) group_ids = api.get_shared_group_ids_by_repo(repo.id) assert group_ids[0] == str(group.id) group_list = api.list_repo_shared_group_by_user(USER, repo.id) assert len(group_list) == 1 group_list = api.list_repo_shared_group_by_user(USER2, repo.id) assert len(group_list) == 0 repo_get = api.get_group_shared_repo_by_path(repo.id, None, group.id) assert repo_get and repo_get.repo_id == repo.id ccnet_api.group_add_member(group.id, USER, USER2) group_list = ccnet_api.get_groups(USER2) assert len(group_list) == 1 group = group_list[0] assert group.id == group.id repos2 = api.get_repos_by_group(group.id) assert_repo_with_permission(repo, repos2, permission) assert api.check_permission(repo.id, USER2) == permission repos = api.get_group_repos_by_user(USER) assert len(repos) == 1 repoids = api.get_group_repoids(group.id) assert len(repoids) == 1 repos = api.get_group_repos_by_owner(USER) assert len(repos) == 1 api.remove_group_repos_by_owner(group.id, USER) repos = api.get_group_repos_by_owner(USER) assert len(repos) == 0 api.set_group_repo(repo.id, group.id, USER, permission) repos = api.get_repos_by_group(group.id) assert len(repos) == 1 api.remove_group_repos(group.id) repos = api.get_repos_by_group(group.id) assert len(repos) == 0 api.group_unshare_repo(repo.id, group.id, USER) repos = api.get_repos_by_group(group.id) assert len(repos) == 0 assert api.check_permission(repo.id, USER2) is None
def libraries(request): """ New URL to replace myhome """ username = request.user.username # options if request.cloud_mode and request.user.org is None: allow_public_share = False else: allow_public_share = True sub_lib_enabled = UserOptions.objects.is_sub_lib_enabled(username) max_upload_file_size = get_max_upload_file_size() guide_enabled = UserOptions.objects.is_user_guide_enabled(username) if guide_enabled: create_default_library(request) folder_perm_enabled = True if is_pro_version( ) and ENABLE_FOLDER_PERM else False if request.cloud_mode and request.user.org is not None: org_id = request.user.org.org_id joined_groups = seaserv.get_org_groups_by_user(org_id, username) else: joined_groups = ccnet_api.get_groups(username, return_ancestors=True) if joined_groups: try: joined_groups.sort(key=lambda x: x.group_name.lower()) except Exception as e: logger.error(e) joined_groups = [] joined_groups_exclude_address_book = [ item for item in joined_groups if item.parent_group_id == 0 ] try: expire_days = seafile_api.get_server_config_int( 'library_trash', 'expire_days') except Exception as e: logger.error(e) expire_days = -1 # Whether use new index page use_new_page = True if request.GET.get('_old', None): use_new_page = False if use_new_page: return react_fake_view(request) return render(request, 'libraries.html', { "allow_public_share": allow_public_share, "guide_enabled": guide_enabled, "sub_lib_enabled": sub_lib_enabled, 'enable_wiki': request.user.permissions.can_use_wiki(), 'enable_upload_folder': settings.ENABLE_UPLOAD_FOLDER, 'enable_resumable_fileupload': settings.ENABLE_RESUMABLE_FILEUPLOAD, 'resumable_upload_file_block_size': settings.RESUMABLE_UPLOAD_FILE_BLOCK_SIZE, 'max_number_of_files_for_fileupload': settings.MAX_NUMBER_OF_FILES_FOR_FILEUPLOAD, 'enable_thumbnail': settings.ENABLE_THUMBNAIL, 'enable_repo_snapshot_label': settings.ENABLE_REPO_SNAPSHOT_LABEL, 'thumbnail_default_size': settings.THUMBNAIL_DEFAULT_SIZE, 'thumbnail_size_for_grid': settings.THUMBNAIL_SIZE_FOR_GRID, 'enable_encrypted_library': config.ENABLE_ENCRYPTED_LIBRARY, 'enable_repo_history_setting': config.ENABLE_REPO_HISTORY_SETTING, 'max_upload_file_size': max_upload_file_size, 'folder_perm_enabled': folder_perm_enabled, 'is_pro': True if is_pro_version() else False, 'file_audit_enabled': FILE_AUDIT_ENABLED, 'can_add_public_repo': request.user.permissions.can_add_public_repo(), 'joined_groups': joined_groups, 'joined_groups_exclude_address_book': joined_groups_exclude_address_book, 'storages': get_library_storages(request), 'unread_notifications_request_interval': UNREAD_NOTIFICATIONS_REQUEST_INTERVAL, 'library_templates': list(LIBRARY_TEMPLATES.keys()) if \ isinstance(LIBRARY_TEMPLATES, dict) else [], 'enable_share_to_all_groups': config.ENABLE_SHARE_TO_ALL_GROUPS, 'enable_group_discussion': settings.ENABLE_GROUP_DISCUSSION, 'enable_file_comment': settings.ENABLE_FILE_COMMENT, 'share_link_expire_days_min': SHARE_LINK_EXPIRE_DAYS_MIN, 'share_link_expire_days_max': SHARE_LINK_EXPIRE_DAYS_MAX, 'share_link_expire_days_default': SHARE_LINK_EXPIRE_DAYS_DEFAULT, 'enable_office_web_app': ENABLE_OFFICE_WEB_APP, 'enable_onlyoffice': ENABLE_ONLYOFFICE, 'trash_repos_expire_days': expire_days if expire_days > 0 else 30, })
def get(self, request): """ List all groups. """ org_id = None username = request.user.username if is_org_context(request): org_id = request.user.org.org_id user_groups = seaserv.get_org_groups_by_user(org_id, username) else: user_groups = ccnet_api.get_groups(username, return_ancestors=True) try: avatar_size = int(request.GET.get('avatar_size', GROUP_AVATAR_DEFAULT_SIZE)) except ValueError: avatar_size = GROUP_AVATAR_DEFAULT_SIZE try: with_repos = int(request.GET.get('with_repos', 0)) except ValueError: with_repos = 0 if with_repos not in (0, 1): error_msg = 'with_repos invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) groups = [] if with_repos: gids = [g.id for g in user_groups] admin_info = ExtraGroupsSharePermission.objects.batch_get_repos_with_admin_permission(gids) for g in user_groups: group_info = get_group_info(request, g.id, avatar_size) if with_repos: if org_id: group_repos = seafile_api.get_org_group_repos(org_id, g.id) else: group_repos = seafile_api.get_repos_by_group(g.id) repos = [] # get repo id owner dict all_repo_owner = [] repo_id_owner_dict = {} for repo in group_repos: repo_id = repo.id if repo_id not in repo_id_owner_dict: repo_owner = get_repo_owner(request, repo_id) all_repo_owner.append(repo_owner) repo_id_owner_dict[repo_id] = repo_owner # Use dict to reduce memcache fetch cost in large for-loop. name_dict = {} contact_email_dict = {} for email in all_repo_owner: if email not in name_dict: if '@seafile_group' in email: group_id = get_group_id_by_repo_owner(email) group_name= group_id_to_name(group_id) name_dict[email] = group_name else: name_dict[email] = email2nickname(email) if email not in contact_email_dict: if '@seafile_group' in email: contact_email_dict[email] = '' else: contact_email_dict[email] = email2contact_email(email) for r in group_repos: repo_owner = repo_id_owner_dict.get(r.id, r.user) repo = { "id": r.id, "repo_id": r.id, "name": r.name, "repo_name": r.name, "size": r.size, "size_formatted": filesizeformat(r.size), "mtime": r.last_modified, "mtime_relative": translate_seahub_time(r.last_modified), "last_modified": timestamp_to_isoformat_timestr(r.last_modified), "encrypted": r.encrypted, "permission": r.permission, "owner": repo_owner, "owner_email": repo_owner, "owner_name": name_dict.get(repo_owner, ''), "owner_contact_email": contact_email_dict.get(repo_owner, ''), "is_admin": (r.id, g.id) in admin_info } repos.append(repo) group_info['repos'] = repos groups.append(group_info) return Response(groups)
def test_user_management(repo): email1 = '%s@%s.com' % (randstring(6), randstring(6)) email2 = '%s@%s.com' % (randstring(6), randstring(6)) passwd1 = 'randstring(6)' passwd2 = 'randstring(6)' ccnet_api.add_emailuser(email1, passwd1, 1, 1) ccnet_api.add_emailuser(email2, passwd2, 0, 0) ccnet_email1 = ccnet_api.get_emailuser(email1) ccnet_email2 = ccnet_api.get_emailuser(email2) assert ccnet_email1.is_active == True assert ccnet_email1.is_staff == True assert ccnet_email2.is_active == False assert ccnet_email2.is_staff == False assert ccnet_api.validate_emailuser(email1, passwd1) == 0 assert ccnet_api.validate_emailuser(email2, passwd2) == 0 users = ccnet_api.search_emailusers('DB', email1, -1, -1) assert len(users) == 1 user_ccnet = users[0] assert user_ccnet.email == email1 user_counts = ccnet_api.count_emailusers('DB') user_numbers = ccnet_api.get_emailusers('DB', -1, -1) ccnet_api.update_emailuser('DB', ccnet_email2.id, passwd2, 1, 1) email2_new = ccnet_api.get_emailuser(email2) assert email2_new.is_active == True assert email2_new.is_staff == True #test group when update user id id1 = ccnet_api.create_group('group1', email1, parent_group_id=-1) assert id1 != -1 group1 = ccnet_api.get_group(id1) assert group1.parent_group_id == -1 # test shared repo when update user id api.share_repo(repo.id, USER, email1, "rw") assert api.repo_has_been_shared(repo.id) new_email1 = '%s@%s.com' % (randstring(6), randstring(6)) assert ccnet_api.update_emailuser_id(email1, new_email1) == 0 shared_users = api.list_repo_shared_to(USER, repo.id) assert len(shared_users) == 1 assert shared_users[0].repo_id == repo.id assert shared_users[0].user == new_email1 assert shared_users[0].perm == "rw" api.remove_share(repo.id, USER, new_email1) email1_groups = ccnet_api.get_groups(new_email1) assert len(email1_groups) == 1 assert email1_groups[0].id == id1 rm1 = ccnet_api.remove_group(id1) assert rm1 == 0 ccnet_api.remove_emailuser('DB', new_email1) ccnet_api.remove_emailuser('DB', email2)