1# Copyright (c) 2012-2016 Seafile Ltd. 2import logging 3from datetime import datetime 4 5from rest_framework.authentication import SessionAuthentication 6from rest_framework.permissions import IsAuthenticated 7from rest_framework.response import Response 8from rest_framework.views import APIView 9from rest_framework import status 10 11from seaserv import seafile_api 12 13from seahub.api2.throttling import UserRateThrottle 14from seahub.api2.authentication import TokenAuthentication 15from seahub.api2.utils import api_error 16from seahub.utils import get_file_history 17from seahub.utils.timeutils import utc_datetime_to_isoformat_timestr, timestamp_to_isoformat_timestr 18from seahub.utils.file_revisions import get_file_revisions_within_limit 19from seahub.views import check_folder_permission 20from seahub.avatar.templatetags.avatar_tags import api_avatar_url 21from seahub.base.templatetags.seahub_tags import email2nickname, \ 22 email2contact_email 23 24logger = logging.getLogger(__name__) 25 26def get_new_file_history_info(ent, avatar_size): 27 28 info = {} 29 30 creator_name = ent.op_user 31 url, is_default, date_uploaded = api_avatar_url(creator_name, avatar_size) 32 33 info['creator_avatar_url'] = url 34 info['creator_email'] = creator_name 35 info['creator_name'] = email2nickname(creator_name) 36 info['creator_contact_email'] = email2contact_email(creator_name) 37 info['op_type'] = ent.op_type 38 info['ctime'] = utc_datetime_to_isoformat_timestr(ent.timestamp) 39 info['commit_id'] = ent.commit_id 40 info['size'] = ent.size 41 info['rev_file_id'] = ent.file_id 42 info['old_path'] = ent.old_path if hasattr(ent, 'old_path') else '' 43 info['path'] = ent.path 44 45 return info 46 47def get_file_history_info(commit, avatar_size): 48 49 info = {} 50 51 creator_name = commit.creator_name 52 url, is_default, date_uploaded = api_avatar_url(creator_name, avatar_size) 53 54 info['creator_avatar_url'] = url 55 info['creator_email'] = creator_name 56 info['creator_name'] = email2nickname(creator_name) 57 info['creator_contact_email'] = email2contact_email(creator_name) 58 info['ctime'] = timestamp_to_isoformat_timestr(commit.ctime) 59 info['description'] = commit.desc 60 info['commit_id'] = commit.id 61 info['size'] = commit.rev_file_size 62 info['rev_file_id'] = commit.rev_file_id 63 info['rev_renamed_old_path'] = commit.rev_renamed_old_path 64 65 return info 66 67 68class FileHistoryView(APIView): 69 authentication_classes = (TokenAuthentication, SessionAuthentication) 70 permission_classes = (IsAuthenticated,) 71 throttle_classes = (UserRateThrottle,) 72 73 def get(self, request, repo_id): 74 """ Get file history within certain commits. 75 Controlled by path(rev_renamed_old_path), commit_id and next_start_commit. 76 """ 77 # argument check 78 path = request.GET.get('path', '') 79 if not path: 80 error_msg = 'path invalid.' 81 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 82 83 # resource check 84 repo = seafile_api.get_repo(repo_id) 85 if not repo: 86 error_msg = 'Library %s not found.' % repo_id 87 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 88 89 commit_id = request.GET.get('commit_id', '') 90 if not commit_id: 91 commit_id = repo.head_cmmt_id 92 93 try: 94 avatar_size = int(request.GET.get('avatar_size', 32)) 95 except ValueError: 96 avatar_size = 32 97 98 # Don't use seafile_api.get_file_id_by_path() 99 # if path parameter is `rev_renamed_old_path`. 100 # seafile_api.get_file_id_by_path() will return None. 101 file_id = seafile_api.get_file_id_by_commit_and_path(repo_id, 102 commit_id, path) 103 if not file_id: 104 error_msg = 'File %s not found.' % path 105 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 106 107 # permission check 108 if not check_folder_permission(request, repo_id, '/'): 109 error_msg = 'Permission denied.' 110 return api_error(status.HTTP_403_FORBIDDEN, error_msg) 111 112 # get repo history limit 113 try: 114 keep_days = seafile_api.get_repo_history_limit(repo_id) 115 except Exception as e: 116 logger.error(e) 117 error_msg = 'Internal Server Error' 118 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 119 120 # get file history 121 limit = request.GET.get('limit', 50) 122 try: 123 limit = 50 if int(limit) < 1 else int(limit) 124 except ValueError: 125 limit = 50 126 127 try: 128 file_revisions, next_start_commit = get_file_revisions_within_limit( 129 repo_id, path, commit_id, limit) 130 except Exception as e: 131 logger.error(e) 132 error_msg = 'Internal Server Error' 133 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 134 135 result = [] 136 present_time = datetime.utcnow() 137 for commit in file_revisions: 138 history_time = datetime.utcfromtimestamp(commit.ctime) 139 if (keep_days != -1) and ((present_time - history_time).days > keep_days): 140 next_start_commit = False 141 break 142 info = get_file_history_info(commit, avatar_size) 143 info['path'] = path 144 result.append(info) 145 146 return Response({ 147 "data": result, 148 "next_start_commit": next_start_commit or False 149 }) 150 151 152class NewFileHistoryView(APIView): 153 authentication_classes = (TokenAuthentication, SessionAuthentication) 154 permission_classes = (IsAuthenticated,) 155 throttle_classes = (UserRateThrottle,) 156 157 def get(self, request, repo_id): 158 """ Get file history within certain commits. 159 160 Controlled by path(rev_renamed_old_path), commit_id and next_start_commit. 161 """ 162 # argument check 163 path = request.GET.get('path', '') 164 if not path: 165 error_msg = 'path invalid.' 166 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 167 168 # resource check 169 repo = seafile_api.get_repo(repo_id) 170 if not repo: 171 error_msg = 'Library %s not found.' % repo_id 172 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 173 174 commit_id = repo.head_cmmt_id 175 176 try: 177 avatar_size = int(request.GET.get('avatar_size', 32)) 178 page = int(request.GET.get('page', '1')) 179 per_page = int(request.GET.get('per_page', '25')) 180 except ValueError: 181 avatar_size = 32 182 page = 1 183 per_page = 25 184 185 # Don't use seafile_api.get_file_id_by_path() 186 # if path parameter is `rev_renamed_old_path`. 187 # seafile_api.get_file_id_by_path() will return None. 188 file_id = seafile_api.get_file_id_by_commit_and_path(repo_id, 189 commit_id, path) 190 if not file_id: 191 error_msg = 'File %s not found.' % path 192 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 193 194 # permission check 195 if not check_folder_permission(request, repo_id, '/'): 196 error_msg = 'Permission denied.' 197 return api_error(status.HTTP_403_FORBIDDEN, error_msg) 198 199 # get repo history limit 200 try: 201 history_limit = seafile_api.get_repo_history_limit(repo_id) 202 except Exception as e: 203 logger.error(e) 204 error_msg = 'Internal Server Error' 205 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 206 207 start = (page - 1) * per_page 208 count = per_page 209 210 try: 211 file_revisions, total_count = get_file_history(repo_id, path, start, count, history_limit) 212 except Exception as e: 213 logger.error(e) 214 error_msg = 'Internal Server Error' 215 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 216 217 data = [get_new_file_history_info(ent, avatar_size) for ent in file_revisions] 218 result = { 219 "data": data, 220 "page": page, 221 "total_count": total_count 222 } 223 224 return Response(result) 225