Coverage for api/constants/restricted_features.py: 94%

30 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-07 06:14 +0000

1import typing 

2from dataclasses import dataclass 

3 

4from rest_framework.request import Request 

5 

6 

7ANONYMOUS: typing.Literal["anonymous"] = "anonymous" 

8AUTHENTICATED: typing.Literal["authenticated"] = "authenticated" 

9PRIVILEGED: typing.Literal["privileged"] = "privileged" 

10 

11AccessLevel = typing.Literal[ANONYMOUS, AUTHENTICATED, PRIVILEGED] 

12ACCESS_LEVELS = typing.get_args(AccessLevel) 

13 

14 

15_RESTRICTED_FEATURES = {} 

16 

17T = typing.TypeVar("T") 

18 

19 

20@dataclass 

21class RestrictedFeature(typing.Generic[T]): 

22 """ 

23 Feature with gradient levels of access granted to applications upon approved request to Openverse maintainers. 

24 

25 Maintainers review requests for increased access to restricted features on a per-case basis. 

26 

27 Distinct from ``rate_limit_model`` which only affects access rates rather than level of access to certain features. 

28 """ 

29 

30 slug: str 

31 anonymous: T 

32 authenticated: T 

33 privileged: T 

34 

35 def __post_init__(self): 

36 _RESTRICTED_FEATURES[self.slug] = self 

37 

38 def request_level(self, request: None | Request) -> tuple[AccessLevel, T]: 

39 """Retrieve the level of any request in relation to the privilege.""" 

40 if request is None or request.auth is None: 

41 return ANONYMOUS, self.anonymous 

42 

43 if self.slug in request.auth.application.privileges: 43 ↛ 44line 43 didn't jump to line 44 because the condition on line 43 was never true

44 return PRIVILEGED, self.privileged 

45 

46 return AUTHENTICATED, self.authenticated 

47 

48 @classmethod 

49 @property 

50 def choices(cls): 

51 return ((slug,) * 2 for slug in _RESTRICTED_FEATURES) 

52 

53 

54MAX_PAGE_SIZE: RestrictedFeature[int] = RestrictedFeature( 

55 "max_page_size", 

56 anonymous=20, 

57 authenticated=50, 

58 # Max out privileged page size at the maximum authenticated 

59 # pagination depth, otherwise privileged page size limit can 

60 # contradict pagination depth limit. 

61 privileged=240, 

62) 

63 

64MAX_RESULT_COUNT: RestrictedFeature[int] = RestrictedFeature( 

65 "max_result_count", 

66 # 12 pages of 20 results 

67 # Both anon and authed are limited to the same depth 

68 # authed users can request bigger pages, but still only the same 

69 # overall number of results available 

70 anonymous=12 * MAX_PAGE_SIZE.anonymous, 

71 authenticated=12 * MAX_PAGE_SIZE.anonymous, 

72 # 20 pages of maxed out page sizes for privileged apps 

73 privileged=20 * MAX_PAGE_SIZE.privileged, 

74)