1# Copyright (c) 2012-2016 Seafile Ltd. 2import logging 3 4from rest_framework.authentication import SessionAuthentication 5from rest_framework.permissions import IsAuthenticated 6from rest_framework.response import Response 7from rest_framework.views import APIView 8from rest_framework import status 9 10import seaserv 11from seaserv import seafile_api, ccnet_api 12 13from seahub.api2.utils import api_error 14from seahub.api2.authentication import TokenAuthentication 15from seahub.api2.throttling import UserRateThrottle 16from seahub.profile.models import Profile 17from seahub.utils import is_org_context, is_valid_username, send_perm_audit_msg 18from seahub.utils.repo import get_available_repo_perms 19from seahub.base.templatetags.seahub_tags import email2nickname, email2contact_email 20from seahub.share.models import ExtraSharePermission, ExtraGroupsSharePermission 21from seahub.share.utils import update_user_dir_permission, update_group_dir_permission,\ 22 check_user_share_out_permission, check_group_share_out_permission 23 24logger = logging.getLogger(__name__) 25 26class SharedRepos(APIView): 27 28 authentication_classes = (TokenAuthentication, SessionAuthentication) 29 permission_classes = (IsAuthenticated,) 30 throttle_classes = (UserRateThrottle,) 31 32 def get(self, request, format=None): 33 """ List all shared out repos. 34 35 Permission checking: 36 1. all authenticated user can perform this action. 37 """ 38 39 shared_repos = [] 40 username = request.user.username 41 try: 42 if is_org_context(request): 43 org_id = request.user.org.org_id 44 shared_repos += seafile_api.get_org_share_out_repo_list(org_id, username, -1, -1) 45 shared_repos += seafile_api.get_org_group_repos_by_owner(org_id, username) 46 shared_repos += seafile_api.list_org_inner_pub_repos_by_owner(org_id, username) 47 else: 48 shared_repos += seafile_api.get_share_out_repo_list(username, -1, -1) 49 shared_repos += seafile_api.get_group_repos_by_owner(username) 50 if not request.cloud_mode: 51 shared_repos += seafile_api.list_inner_pub_repos_by_owner(username) 52 except Exception as e: 53 logger.error(e) 54 error_msg = 'Internal Server Error' 55 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 56 57 returned_result = [] 58 shared_repos.sort(key=lambda x: x.repo_name) 59 usernames = [] 60 gids = [] 61 for repo in shared_repos: 62 if repo.is_virtual: 63 continue 64 65 result = {} 66 result['repo_id'] = repo.repo_id 67 result['repo_name'] = repo.repo_name 68 result['encrypted'] = repo.encrypted 69 result['share_type'] = repo.share_type 70 result['share_permission'] = repo.permission 71 result['modifier_email'] = repo.last_modifier 72 result['modifier_name'] = email2nickname(repo.last_modifier) 73 result['modifier_contact_email'] = email2contact_email(repo.last_modifier) 74 75 if repo.share_type == 'personal': 76 result['user_name'] = email2nickname(repo.user) 77 result['user_email'] = repo.user 78 result['contact_email'] = Profile.objects.get_contact_email_by_user(repo.user) 79 usernames.append((repo.repo_id, repo.user)) 80 81 if repo.share_type == 'group': 82 group = ccnet_api.get_group(repo.group_id) 83 result['group_id'] = repo.group_id 84 result['group_name'] = group.group_name if group else '' 85 gids.append(repo.group_id) 86 87 returned_result.append(result) 88 89 user_admins = ExtraSharePermission.objects.batch_is_admin(usernames) 90 group_admins = ExtraGroupsSharePermission.objects.batch_get_repos_with_admin_permission(gids) 91 for result in returned_result: 92 if result['share_type'] == 'group': 93 result['is_admin'] = (result['repo_id'], result['group_id']) in group_admins 94 elif result['share_type'] == 'personal': 95 result['is_admin'] = (result['repo_id'], result['user_email']) in user_admins 96 97 return Response(returned_result) 98 99 100class SharedRepo(APIView): 101 authentication_classes = (TokenAuthentication, SessionAuthentication) 102 permission_classes = (IsAuthenticated,) 103 throttle_classes = (UserRateThrottle,) 104 105 def put(self, request, repo_id, format=None): 106 """ Update permission of a shared repo. 107 108 Permission checking: 109 1. Only repo owner can update. 110 """ 111 112 # argument check 113 permission = request.data.get('permission', None) 114 if permission not in get_available_repo_perms(): 115 error_msg = 'permission invalid.' 116 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 117 118 share_type = request.data.get('share_type', None) 119 if not share_type: 120 error_msg = 'share_type invalid.' 121 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 122 123 if share_type not in ('personal', 'group', 'public'): 124 error_msg = "share_type can only be 'personal' or 'group' or 'public'." 125 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 126 127 # recourse check 128 repo = seafile_api.get_repo(repo_id) 129 if not repo: 130 error_msg = 'Library %s not found.' % repo_id 131 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 132 133 # permission check 134 username = request.user.username 135 if is_org_context(request): 136 repo_owner = seafile_api.get_org_repo_owner(repo_id) 137 else: 138 repo_owner = seafile_api.get_repo_owner(repo_id) 139 140 if username != repo_owner: 141 error_msg = 'Permission denied.' 142 return api_error(status.HTTP_403_FORBIDDEN, error_msg) 143 144 # update share permission 145 if share_type == 'personal': 146 shared_to = request.data.get('user', None) 147 if not shared_to or not is_valid_username(shared_to): 148 error_msg = 'user invalid.' 149 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 150 151 try: 152 if is_org_context(request): 153 org_id = request.user.org.org_id 154 update_user_dir_permission(repo_id, '/', repo_owner, shared_to, permission, org_id) 155 else: 156 update_user_dir_permission(repo_id, '/', repo_owner, shared_to, permission) 157 except Exception as e: 158 logger.error(e) 159 error_msg = 'Internal Server Error' 160 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 161 162 send_perm_audit_msg('modify-repo-perm', username, 163 shared_to, repo_id, '/', permission) 164 165 if share_type == 'group': 166 group_id = request.data.get('group_id', None) 167 if not group_id: 168 error_msg = 'group_id invalid.' 169 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 170 171 try: 172 group_id = int(group_id) 173 except ValueError: 174 error_msg = 'group_id must be integer.' 175 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 176 177 group = ccnet_api.get_group(group_id) 178 if not group: 179 error_msg = 'Group %s not found.' % group_id 180 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 181 182 try: 183 if is_org_context(request): 184 org_id = request.user.org.org_id 185 update_group_dir_permission(repo_id, '/', repo_owner, group_id, permission, org_id) 186 else: 187 update_group_dir_permission(repo_id, '/', repo_owner, group_id, permission) 188 except Exception as e: 189 logger.error(e) 190 error_msg = 'Internal Server Error' 191 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 192 193 send_perm_audit_msg('modify-repo-perm', username, 194 group_id, repo_id, '/', permission) 195 196 if share_type == 'public': 197 198 try: 199 if is_org_context(request): 200 org_id = request.user.org.org_id 201 seafile_api.set_org_inner_pub_repo(org_id, repo_id, permission) 202 else: 203 if not request.user.permissions.can_add_public_repo(): 204 error_msg = 'Permission denied.' 205 return api_error(status.HTTP_403_FORBIDDEN, error_msg) 206 207 seafile_api.add_inner_pub_repo(repo_id, permission) 208 209 except Exception as e: 210 logger.error(e) 211 error_msg = 'Internal Server Error' 212 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 213 214 send_perm_audit_msg('modify-repo-perm', username, 215 'all', repo_id, '/', permission) 216 217 return Response({'success': True}) 218 219 def delete(self, request, repo_id, format=None): 220 """ Unshare a repo. 221 222 Permission checking: 223 1. Only repo owner and system admin can unshare a publib library. 224 """ 225 226 # argument check 227 share_type = request.GET.get('share_type', None) 228 if not share_type: 229 error_msg = 'share_type invalid.' 230 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 231 232 if share_type not in ('personal', 'group', 'public'): 233 error_msg = "share_type can only be 'personal' or 'group' or 'public'." 234 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 235 236 # resource check 237 repo = seafile_api.get_repo(repo_id) 238 if not repo: 239 return api_error(status.HTTP_404_NOT_FOUND, 'Library %s not found.' % repo_id) 240 241 # permission check 242 username = request.user.username 243 if is_org_context(request): 244 repo_owner = seafile_api.get_org_repo_owner(repo_id) 245 else: 246 repo_owner = seafile_api.get_repo_owner(repo_id) 247 248 if not request.user.is_staff and not username == repo_owner: 249 error_msg = 'Permission denied.' 250 return api_error(status.HTTP_403_FORBIDDEN, error_msg) 251 252 # delete share 253 org_id = None 254 is_org = False 255 if is_org_context(request): 256 org_id = request.user.org.org_id 257 is_org = True 258 259 if share_type == 'personal': 260 user = request.GET.get('user', None) 261 if not user or not is_valid_username(user): 262 error_msg = 'user invalid.' 263 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 264 265 permission = check_user_share_out_permission(repo_id, '/', user, is_org) 266 267 try: 268 if org_id: 269 seafile_api.org_remove_share(org_id, repo_id, 270 username, user) 271 else: 272 seafile_api.remove_share(repo_id, username, user) 273 except Exception as e: 274 logger.error(e) 275 error_msg = 'Internal Server Error' 276 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 277 278 send_perm_audit_msg('delete-repo-perm', username, user, 279 repo_id, '/', permission) 280 281 if share_type == 'group': 282 group_id = request.GET.get('group_id', None) 283 if not group_id: 284 error_msg = 'group_id invalid.' 285 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 286 287 try: 288 group_id = int(group_id) 289 except ValueError: 290 error_msg = 'group_id must be integer.' 291 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 292 293 permission = check_group_share_out_permission(repo_id, '/', group_id, is_org) 294 295 296 try: 297 if is_org: 298 seaserv.del_org_group_repo(repo_id, org_id, group_id) 299 else: 300 seafile_api.unset_group_repo(repo_id, group_id, username) 301 except Exception as e: 302 logger.error(e) 303 error_msg = 'Internal Server Error' 304 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 305 306 send_perm_audit_msg('delete-repo-perm', username, group_id, 307 repo_id, '/', permission) 308 309 if share_type == 'public': 310 pub_repos = [] 311 if org_id: 312 pub_repos = seafile_api.list_org_inner_pub_repos(org_id) 313 314 if not request.cloud_mode: 315 pub_repos = seafile_api.get_inner_pub_repo_list() 316 317 try: 318 if org_id: 319 seaserv.seafserv_threaded_rpc.unset_org_inner_pub_repo(org_id, repo_id) 320 else: 321 seafile_api.remove_inner_pub_repo(repo_id) 322 except Exception as e: 323 logger.error(e) 324 error_msg = 'Internal Server Error' 325 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 326 327 permission = '' 328 for repo in pub_repos: 329 if repo.repo_id == repo_id: 330 permission = repo.permission 331 break 332 333 if permission: 334 send_perm_audit_msg('delete-repo-perm', username, 'all', repo_id, '/', permission) 335 336 return Response({'success': True}) 337