1# Copyright (c) 2012-2016 Seafile Ltd. 2# -*- coding: utf-8 -*- 3from datetime import datetime 4import logging 5 6from django.db import models 7 8from seahub.base.fields import LowerCaseCharField 9from seahub.utils import is_pro_version 10 11# Get an instance of a logger 12logger = logging.getLogger(__name__) 13 14KEY_SERVER_CRYPTO = "server_crypto" 15VAL_SERVER_CRYPTO_ENABLED = "1" 16VAL_SERVER_CRYPTO_DISABLED = "0" 17 18KEY_USER_GUIDE = "user_guide" 19VAL_USER_GUIDE_ON = "1" 20VAL_USER_GUIDE_OFF = "0" 21 22KEY_SUB_LIB = "sub_lib" 23VAL_SUB_LIB_ENABLED = "1" 24VAL_SUB_LIB_DISABLED = "0" 25 26KEY_FORCE_PASSWD_CHANGE = "force_passwd_change" 27VAL_FORCE_PASSWD_CHANGE = "1" 28 29KEY_FORCE_2FA = "force_2fa" 30VAL_FORCE_2FA = "1" 31 32KEY_USER_LOGGED_IN = "user_logged_in" 33VAL_USER_LOGGED_IN = "1" 34 35KEY_DEFAULT_REPO = "default_repo" 36KEY_WEBDAV_SECRET = "webdav_secret" 37KEY_FILE_UPDATES_EMAIL_INTERVAL = "file_updates_email_interval" 38KEY_FILE_UPDATES_LAST_EMAILED_TIME = "file_updates_last_emailed_time" 39KEY_COLLABORATE_EMAIL_INTERVAL = 'collaborate_email_interval' 40KEY_COLLABORATE_LAST_EMAILED_TIME = 'collaborate_last_emailed_time' 41 42DEFAULT_COLLABORATE_EMAIL_INTERVAL = 3600 43 44 45class CryptoOptionNotSetError(Exception): 46 pass 47 48class UserOptionsManager(models.Manager): 49 def set_user_option(self, username, k, v): 50 """ 51 52 Arguments: 53 - `username`: 54 - `k`: 55 - `v`: 56 """ 57 try: 58 user_option = super(UserOptionsManager, self).get(email=username, 59 option_key=k) 60 user_option.option_val = v 61 except UserOptions.DoesNotExist: 62 user_option = self.model(email=username, option_key=k, 63 option_val=v) 64 user_option.save(using=self._db) 65 66 return user_option 67 68 def get_user_option(self, username, k): 69 user_options = super(UserOptionsManager, self).filter( 70 email=username, option_key=k) 71 72 if len(user_options) == 0: 73 return None 74 elif len(user_options) == 1: 75 return user_options[0].option_val 76 else: 77 for o in user_options[1: len(user_options)]: 78 o.delete() 79 80 return user_options[0].option_val 81 82 def unset_user_option(self, username, k): 83 """Remove user's option. 84 """ 85 super(UserOptionsManager, self).filter(email=username, option_key=k).delete() 86 87 def enable_server_crypto(self, username): 88 """ 89 90 Arguments: 91 - `username`: 92 """ 93 return self.set_user_option(username, KEY_SERVER_CRYPTO, 94 VAL_SERVER_CRYPTO_ENABLED) 95 96 def disable_server_crypto(self, username): 97 """ 98 99 Arguments: 100 - `username`: 101 """ 102 return self.set_user_option(username, KEY_SERVER_CRYPTO, 103 VAL_SERVER_CRYPTO_DISABLED) 104 105 def is_server_crypto(self, username): 106 """Client crypto is deprecated, always return ``True``. 107 """ 108 return True 109 110 def enable_user_guide(self, username): 111 """ 112 113 Arguments: 114 - `self`: 115 - `username`: 116 """ 117 return self.set_user_option(username, KEY_USER_GUIDE, 118 VAL_USER_GUIDE_ON) 119 120 def disable_user_guide(self, username): 121 """ 122 123 Arguments: 124 - `self`: 125 - `username`: 126 """ 127 return self.set_user_option(username, KEY_USER_GUIDE, 128 VAL_USER_GUIDE_OFF) 129 130 def is_user_guide_enabled(self, username): 131 """Return ``True`` if user need guide, otherwise ``False``. 132 133 Arguments: 134 - `self`: 135 - `username`: 136 """ 137 rst = super(UserOptionsManager, self).filter( 138 email=username, option_key=KEY_USER_GUIDE) 139 rst_len = len(rst) 140 if rst_len <= 0: 141 # Assume ``user_guide`` is enabled if this optoin is not set. 142 return True 143 elif rst_len == 1: 144 return bool(int(rst[0].option_val)) 145 else: 146 for i in range(rst_len - 1): 147 rst[i].delete() 148 return bool(int(rst[rst_len - 1].option_val)) 149 150 def enable_sub_lib(self, username): 151 """ 152 153 Arguments: 154 - `self`: 155 - `username`: 156 """ 157 return self.set_user_option(username, KEY_SUB_LIB, 158 VAL_SUB_LIB_ENABLED) 159 160 def disable_sub_lib(self, username): 161 """ 162 163 Arguments: 164 - `self`: 165 - `username`: 166 """ 167 return self.set_user_option(username, KEY_SUB_LIB, 168 VAL_SUB_LIB_DISABLED) 169 170 def is_sub_lib_enabled(self, username): 171 """Return ``True`` if is not pro version AND sub lib enabled, otherwise ``False``. 172 173 Arguments: 174 - `self`: 175 - `username`: 176 """ 177 if is_pro_version(): 178 return False 179 180 try: 181 user_option = super(UserOptionsManager, self).get( 182 email=username, option_key=KEY_SUB_LIB) 183 return bool(int(user_option.option_val)) 184 except UserOptions.DoesNotExist: 185 return False 186 187 def set_default_repo(self, username, repo_id): 188 """Set a user's default library. 189 190 Arguments: 191 - `self`: 192 - `username`: 193 - `repo_id`: 194 """ 195 return self.set_user_option(username, KEY_DEFAULT_REPO, repo_id) 196 197 def get_default_repo(self, username): 198 """Get a user's default library. 199 200 Returns repo_id if default library is found, otherwise ``None``. 201 202 Arguments: 203 - `self`: 204 - `username`: 205 """ 206 return self.get_user_option(username, KEY_DEFAULT_REPO) 207 208 def passwd_change_required(self, username): 209 """Check whether user need to change password. 210 """ 211 try: 212 r = super(UserOptionsManager, self).get( 213 email=username, option_key=KEY_FORCE_PASSWD_CHANGE) 214 return r.option_val == VAL_FORCE_PASSWD_CHANGE 215 except UserOptions.DoesNotExist: 216 return False 217 218 def set_force_passwd_change(self, username): 219 return self.set_user_option(username, KEY_FORCE_PASSWD_CHANGE, 220 VAL_FORCE_PASSWD_CHANGE) 221 222 def unset_force_passwd_change(self, username): 223 return self.unset_user_option(username, KEY_FORCE_PASSWD_CHANGE) 224 225 def set_force_2fa(self, username): 226 return self.set_user_option(username, KEY_FORCE_2FA, VAL_FORCE_2FA) 227 228 def unset_force_2fa(self, username): 229 return self.unset_user_option(username, KEY_FORCE_2FA) 230 231 def is_force_2fa(self, username): 232 r = super(UserOptionsManager, self).filter(email=username, 233 option_key=KEY_FORCE_2FA) 234 return True if len(r) > 0 else False 235 236 def set_user_logged_in(self, username): 237 return self.set_user_option(username, KEY_USER_LOGGED_IN, 238 VAL_USER_LOGGED_IN) 239 240 def is_user_logged_in(self, username): 241 """Check whether user has logged in successfully at least once. 242 """ 243 try: 244 r = super(UserOptionsManager, self).get( 245 email=username, option_key=KEY_USER_LOGGED_IN) 246 return r.option_val == VAL_USER_LOGGED_IN 247 except UserOptions.DoesNotExist: 248 return False 249 250 def set_webdav_secret(self, username, secret): 251 return self.set_user_option(username, KEY_WEBDAV_SECRET, 252 secret) 253 254 def unset_webdav_secret(self, username): 255 return self.unset_user_option(username, KEY_WEBDAV_SECRET) 256 257 def get_webdav_secret(self, username): 258 try: 259 r = super(UserOptionsManager, self).get( 260 email=username, option_key=KEY_WEBDAV_SECRET 261 ) 262 return r.option_val 263 except UserOptions.DoesNotExist: 264 return None 265 266 def get_webdav_decoded_secret(self, username): 267 from seahub.utils.hasher import AESPasswordHasher 268 269 secret = UserOptions.objects.get_webdav_secret(username) 270 if secret: 271 aes = AESPasswordHasher() 272 decoded = aes.decode(secret) 273 else: 274 decoded = None 275 return decoded 276 277 def set_file_updates_email_interval(self, username, seconds): 278 return self.set_user_option(username, KEY_FILE_UPDATES_EMAIL_INTERVAL, 279 str(seconds)) 280 281 def get_file_updates_email_interval(self, username): 282 val = self.get_user_option(username, KEY_FILE_UPDATES_EMAIL_INTERVAL) 283 if not val: 284 return None 285 try: 286 return int(val) 287 except ValueError: 288 logger.error('Failed to convert string %s to int' % val) 289 return None 290 291 def unset_file_updates_email_interval(self, username): 292 return self.unset_user_option(username, KEY_FILE_UPDATES_EMAIL_INTERVAL) 293 294 def set_file_updates_last_emailed_time(self, username, time_dt): 295 return self.set_user_option( 296 username, KEY_FILE_UPDATES_LAST_EMAILED_TIME, 297 time_dt.strftime("%Y-%m-%d %H:%M:%S")) 298 299 def get_file_updates_last_emailed_time(self, username): 300 val = self.get_user_option(username, KEY_FILE_UPDATES_LAST_EMAILED_TIME) 301 if not val: 302 return None 303 304 try: 305 return datetime.strptime(val, "%Y-%m-%d %H:%M:%S") 306 except Exception: 307 logger.error('Failed to convert string %s to datetime obj' % val) 308 return None 309 310 def unset_file_updates_last_emailed_time(self, username): 311 return self.unset_user_option(username, KEY_FILE_UPDATES_LAST_EMAILED_TIME) 312 313 def set_collaborate_email_interval(self, username, seconds): 314 return self.set_user_option(username, KEY_COLLABORATE_EMAIL_INTERVAL, 315 str(seconds)) 316 317 def get_collaborate_email_interval(self, username): 318 val = self.get_user_option(username, KEY_COLLABORATE_EMAIL_INTERVAL) 319 if not val: 320 return None 321 try: 322 return int(val) 323 except ValueError: 324 logger.error('Failed to convert string %s to int' % val) 325 return None 326 327 def unset_collaborate_email_interval(self, username): 328 return self.unset_user_option(username, KEY_COLLABORATE_EMAIL_INTERVAL) 329 330 def set_collaborate_last_emailed_time(self, username, time_dt): 331 return self.set_user_option( 332 username, KEY_COLLABORATE_LAST_EMAILED_TIME, 333 time_dt.strftime("%Y-%m-%d %H:%M:%S")) 334 335 def get_collaborate_last_emailed_time(self, username): 336 val = self.get_user_option(username, KEY_COLLABORATE_LAST_EMAILED_TIME) 337 if not val: 338 return None 339 340 try: 341 return datetime.strptime(val, "%Y-%m-%d %H:%M:%S") 342 except Exception: 343 logger.error('Failed to convert string %s to datetime obj' % val) 344 return None 345 346 def unset_collaborate_last_emailed_time(self, username): 347 return self.unset_user_option(username, KEY_COLLABORATE_LAST_EMAILED_TIME) 348 349 350class UserOptions(models.Model): 351 email = LowerCaseCharField(max_length=255, db_index=True) 352 option_key = models.CharField(max_length=50, db_index=True) 353 option_val = models.CharField(max_length=50) 354 355 objects = UserOptionsManager() 356