django-restit 4.2.92__py3-none-any.whl → 4.2.94__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
account/fcm/__init__.py CHANGED
@@ -1,33 +1 @@
1
- import requests
2
- from rest import settings
3
- from rest import log
4
-
5
- # SEND_URL = "POST https://fcm.googleapis.com/v1/{parent=projects/*}/messages:send"
6
- SEND_URL = "https://fcm.googleapis.com/fcm/send"
7
- CM_PROVIDERS = settings.get("CM_PROVIDERS", None)
8
-
9
- FCM_KEY = CM_PROVIDERS["fcm"]["key"]
10
-
11
- logger = log.getLogger("fcm", filename="fcm.log")
12
-
13
-
14
- def sendToDevice(device, data):
15
- return sendData(device.cm_token, data)
16
-
17
-
18
- def sendNotification(to_token, title, body):
19
- return postMessage(dict(to=to_token, notification=dict(title=title, body=body)))
20
-
21
-
22
- def sendData(to_token, data, priority="high"):
23
- return postMessage(dict(to=to_token, data=data, content_available=True, priority=priority))
24
-
25
-
26
- def postMessage(payload):
27
- logger.info("sending FCM", payload)
28
- headers = dict(Authorization=F"key={FCM_KEY}")
29
- headers['Content-type'] = 'application/json'
30
- resp = requests.post(SEND_URL, json=payload, headers=headers)
31
- logger.info("response", resp.text)
32
- return resp
33
-
1
+ from . import v1
account/fcm/legacy.py ADDED
@@ -0,0 +1,35 @@
1
+ import requests
2
+ from rest import settings
3
+ from rest import log
4
+
5
+
6
+ SEND_URL = "https://fcm.googleapis.com/fcm/send"
7
+ CM_PROVIDERS = settings.get("CM_PROVIDERS", None)
8
+
9
+ FCM_KEY = None
10
+ if CM_PROVIDERS and "fcm" in CM_PROVIDERS:
11
+ FCM_KEY = CM_PROVIDERS["fcm"]["key"]
12
+
13
+ logger = log.getLogger("fcm", filename="fcm.log")
14
+
15
+
16
+ def sendToDevice(device, data):
17
+ return sendData(device.cm_token, data)
18
+
19
+
20
+ def sendNotification(to_token, title, body):
21
+ return postMessage(dict(to=to_token, notification=dict(title=title, body=body)))
22
+
23
+
24
+ def sendData(to_token, data, priority="high"):
25
+ return postMessage(dict(to=to_token, data=data, content_available=True, priority=priority))
26
+
27
+
28
+ def postMessage(payload):
29
+ logger.info("sending FCM", payload)
30
+ headers = dict(Authorization=F"key={FCM_KEY}")
31
+ headers['Content-type'] = 'application/json'
32
+ resp = requests.post(SEND_URL, json=payload, headers=headers)
33
+ logger.info("response", resp.text)
34
+ return resp
35
+
account/fcm/v1.py CHANGED
@@ -1,47 +1,105 @@
1
- from google.oauth2 import service_account
2
- import google.auth.transport.requests
1
+ import json
2
+ import time
3
+ import jwt # PyJWT library
3
4
  import requests
4
- from rest import settings
5
- from rest import log
6
5
 
7
6
 
8
- FCM_ENDPOINT = 'https://fcm.googleapis.com/v1/projects/{}/messages:send'
9
-
10
- logger = log.getLogger("fcm", filename="fcm.log")
11
-
12
-
13
- def getCredentials(data):
14
- # Load the credentials from the dictionary
15
- credentials = service_account.Credentials.from_service_account_info(
16
- data,
17
- scopes=["https://www.googleapis.com/auth/firebase.messaging"])
18
- # Use the credentials to authenticate a Requests session
19
- auth_req = google.auth.transport.requests.Request()
20
- credentials.refresh(auth_req)
21
- return credentials
22
-
23
-
24
- def sendToDevice(device, data):
25
- return sendData(device.cm_token, data)
26
-
27
-
28
- def sendNotification(to_token, title, body):
29
- return postMessage(dict(token=to_token, notification=dict(title=title, body=body)))
30
-
31
-
32
- def sendData(to_token, data, priority="high"):
33
- return postMessage(dict(token=to_token, data=data, content_available=True, priority=priority))
34
-
7
+ def create_jwt(service_account_info):
8
+ """
9
+ Create a JWT (JSON Web Token) for service account authentication.
10
+
11
+ :param service_account_info: Dictionary containing service account credentials.
12
+ :return: JWT string.
13
+ """
14
+ now = int(time.time())
15
+ payload = {
16
+ 'iss': service_account_info['client_email'],
17
+ 'sub': service_account_info['client_email'],
18
+ 'aud': 'https://oauth2.googleapis.com/token',
19
+ 'iat': now,
20
+ 'exp': now + 3600,
21
+ 'scope': 'https://www.googleapis.com/auth/firebase.messaging'
22
+ }
23
+
24
+ additional_headers = {
25
+ 'kid': service_account_info['private_key_id']
26
+ }
27
+
28
+ token = jwt.encode(payload, service_account_info['private_key'], algorithm='RS256', headers=additional_headers)
29
+ return token
35
30
 
36
- def postMessage(credentials, payload):
37
- logger.info("sending FCM", payload)
31
+ def get_access_token(jwt_token):
32
+ """
33
+ Exchange a JWT for an access token.
34
+
35
+ :param jwt_token: JWT string.
36
+ :return: Access token string.
37
+ """
38
+ url = 'https://oauth2.googleapis.com/token'
38
39
  headers = {
39
- 'Authorization': 'Bearer ' + credentials.token,
40
- 'Content-Type': 'application/json; UTF-8',
40
+ 'Content-Type': 'application/x-www-form-urlencoded'
41
+ }
42
+ payload = {
43
+ 'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
44
+ 'assertion': jwt_token
41
45
  }
42
- body = dict(message=payload)
43
- resp = requests.post(FCM_ENDPOINT.format(credentials.project_id), headers=headers, json=body)
44
- logger.info("response", resp.text)
45
- return resp
46
+
47
+ response = requests.post(url, headers=headers, data=payload)
48
+ response_data = response.json()
49
+ return response_data['access_token']
46
50
 
51
+ class FirebaseNotifier:
52
+ def __init__(self, service_account_info):
53
+ """
54
+ Initialize the FirebaseNotifier with the project ID and service account info.
55
+
56
+ :param project_id: The project ID from Firebase project settings.
57
+ :param service_account_info: Dictionary containing service account credentials.
58
+ """
59
+ self.project_id = service_account_info.get("project_id")
60
+ self.service_account_info = service_account_info
61
+ self.fcm_url = f'https://fcm.googleapis.com/v1/projects/{self.project_id}/messages:send'
62
+ self.jwt_token = None
63
+ self._jwt_expires = 0
64
+ self.access_token = None
47
65
 
66
+ @property
67
+ def is_jwt_expired(self):
68
+ return time.time() > self._jwt_expires
69
+
70
+
71
+ def _get_access_token(self):
72
+ """
73
+ Get the access token, refreshing if necessary.
74
+
75
+ :return: Access token string.
76
+ """
77
+ if not self.jwt_token or self.is_jwt_expired:
78
+ self.jwt_token = create_jwt(self.service_account_info)
79
+ self._jwt_expires = time.time() + 3000
80
+ self.access_token = get_access_token(self.jwt_token)
81
+ return self.access_token
82
+
83
+ def send(self, registration_token, title, body, data=None):
84
+ """
85
+ Send a notification to the specified registration token.
86
+
87
+ :param registration_token: Device registration token.
88
+ :param title: Title of the notification.
89
+ :param body: Body of the notification.
90
+ :param data: Optional data payload to send along with the notification.
91
+ :return: Response from the FCM server.
92
+ """
93
+ access_token = self._get_access_token()
94
+ headers = {
95
+ 'Content-Type': 'application/json',
96
+ 'Authorization': f'Bearer {access_token}',
97
+ }
98
+ message = dict(token=registration_token)
99
+ if title and body:
100
+ message["notification"] = dict(title=title, body=body)
101
+ if data:
102
+ message["data"] = data
103
+ payload = dict(message=message)
104
+ response = requests.post(self.fcm_url, headers=headers, data=json.dumps(payload))
105
+ return response.json()
@@ -0,0 +1,19 @@
1
+ # Generated by Django 4.1.5 on 2024-06-07 20:05
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('account', '0020_cloudcredentials_cloudcredentialsmetadata'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name='cloudcredentials',
16
+ name='group',
17
+ field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cloud_credentials', to='account.group'),
18
+ ),
19
+ ]
account/models/device.py CHANGED
@@ -39,13 +39,13 @@ class MemberDevice(models.Model, rm.RestModel, rm.MetaDataModel):
39
39
  }
40
40
 
41
41
  def sendData(self, message, **kwargs):
42
- messenger = getCloudMessanger(self.cm_provider)
42
+ messenger = getCloudMessenger(self.cm_provider)
43
43
  if messenger:
44
44
  return messenger.sendToDevice(self, message)
45
45
  return objict(status_code=404, reason=self.cm_provider)
46
46
 
47
47
  def sendNotification(self, title, body):
48
- messenger = getCloudMessanger(self.cm_provider)
48
+ messenger = getCloudMessenger(self.cm_provider)
49
49
  if messenger:
50
50
  return messenger.sendNotification(self.cm_token, title, body)
51
51
  return objict(status_code=404, reason=self.cm_provider)
@@ -129,7 +129,9 @@ class CloudCredentials(models.Model, rm.RestModel, rm.MetaDataModel):
129
129
 
130
130
  created = models.DateTimeField(auto_now_add=True)
131
131
  modified = models.DateTimeField(auto_now=True)
132
- group = models.ForeignKey("account.Group", related_name="cloud_credentials", on_delete=models.CASCADE)
132
+ group = models.ForeignKey(
133
+ "account.Group", null=True, default=None,
134
+ related_name="cloud_credentials", on_delete=models.CASCADE)
133
135
 
134
136
  name = models.CharField(max_length=128, blank=True, null=True, default=None)
135
137
  uuid = models.CharField(db_index=True, max_length=64, blank=True, null=True, default=None)
@@ -137,23 +139,28 @@ class CloudCredentials(models.Model, rm.RestModel, rm.MetaDataModel):
137
139
 
138
140
  credentials = rf.JSONField()
139
141
 
142
+ _notifier = None
143
+
144
+ @property
145
+ def notifier(self):
146
+ if self._notifier is None:
147
+ from account import fcm
148
+ self._notifier = fcm.v1.FirebaseNotifier(self.credentials)
149
+ return self._notifier
150
+
140
151
  def sendToDevice(self, device, message):
141
- pass
152
+ self.notifier.send(device.cm_token, None, None, message)
142
153
 
143
154
  def sendNotification(self, token, title, body):
144
- pass
155
+ self.notifier.send(token, title, body)
145
156
 
146
157
 
147
158
  class CloudCredentialsMetaData(rm.MetaDataBase):
148
159
  parent = models.ForeignKey(CloudCredentials, related_name="properties", on_delete=models.CASCADE)
149
160
 
150
161
 
151
- def getCloudMessanger(name):
152
- # creds = CloudCredentials.objects.filter(uuid=name).last()
153
- # if creds is not None:
154
- # return creds
155
- if name not in CM_BACKENDS:
156
- if name == "fcm":
157
- from account import fcm
158
- CM_BACKENDS["fcm"] = fcm
159
- return CM_BACKENDS.get(name, None)
162
+ def getCloudMessenger(name):
163
+ creds = CloudCredentials.objects.filter(uuid=name).last()
164
+ if creds is not None:
165
+ return creds
166
+ return None
account/rpc/device.py CHANGED
@@ -19,33 +19,12 @@ def rest_on_member_device(request, pk=None):
19
19
  return am.MemberDevice.on_rest_request(request, pk)
20
20
 
21
21
 
22
- @rd.urlPOST(r'^member/device/register$')
22
+ @rd.urlPOST('member/device/register')
23
23
  @rd.login_required
24
24
  def rest_on_member_device_register(request):
25
25
  # this requires a JWT with a device_id
26
26
  if not request.device_id:
27
27
  return rv.restPermissionDenied(request, "requires jwt with device id")
28
- cm_token = request.DATA.get("cm_token")
29
- device_id = request.device_id
30
- if not device_id:
31
- return rv.restStatus(request, False, error="missing device id")
32
- md = am.MemberDevice.objects.filter(uuid=device_id).last()
33
- if md is None:
34
- md = am.MemberDevice.createFromRequest(request, uuid=device_id, user=request.member)
35
- elif cm_token is not None and md.cm_token != cm_token:
36
- md.cm_token = cm_token
37
- md.cm_provider = "fcm"
38
- md.save()
39
- return rv.restStatus(request, True)
40
-
41
-
42
- @rd.urlPOST(r'^member/device/register$')
43
- @rd.login_required
44
- def rest_on_member_device_register(request):
45
- # this requires a JWT with a device_id
46
- if not request.device_id:
47
- return rv.restPermissionDenied(request, "requires jwt with device id")
48
-
49
28
  md = am.MemberDevice.register(request, request.member, request.device_id)
50
29
  return rv.restStatus(request, md is not None)
51
30
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-restit
3
- Version: 4.2.92
3
+ Version: 4.2.94
4
4
  Summary: A Rest Framework for DJANGO
5
5
  License: MIT
6
6
  Author: Ian Starnes
@@ -21,7 +21,7 @@ Requires-Dist: fido2
21
21
  Requires-Dist: gevent (>=23.7.0,<24.0.0)
22
22
  Requires-Dist: hashids (>=1.3.1,<2.0.0)
23
23
  Requires-Dist: inlinestyler
24
- Requires-Dist: mistune
24
+ Requires-Dist: mistune (>=2.0.4,<3.0.0)
25
25
  Requires-Dist: phonenumbers
26
26
  Requires-Dist: pillow
27
27
  Requires-Dist: psutil
@@ -1,8 +1,8 @@
1
1
  account/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  account/admin.py,sha256=8MQ1gAgjpPUC_SGCVMwd7I8fqLetqcutLiasjssEPRY,1839
3
- account/fcm/__init__.py,sha256=gSTChf99a5T20oKuf4Lh9UR-f3V5qI20AZxIhlPlnVs,980
4
- account/fcm/google.py,sha256=T-TZZgrT90YY9sEtKC6rNGpwfBmVTCuFpB31vRDguu0,1710
5
- account/fcm/v1.py,sha256=PGpSmAnq40cMao4SwDU2tv6m5PpteDWLbzvldjalRJ8,1434
3
+ account/fcm/__init__.py,sha256=lXuz5z0bL5TXqVdaXxiVr-4zF_Q1IZ8kPEkuYGb5eB0,17
4
+ account/fcm/legacy.py,sha256=5WM5HAnjVPweT0oe3rBN9tBGHfC-DPa-e9luH3baT8Y,959
5
+ account/fcm/v1.py,sha256=Z4hTmx1BIcmuVtW52QMmqHtQO5-yHMRCNy9GLAsy32Y,3610
6
6
  account/migrations/0001_initial.py,sha256=PhYNDTiwjyUplErBmYc34ecynLIEJL2JuC02o8GCXes,15894
7
7
  account/migrations/0003_member_phone_number.py,sha256=auAJCfxsK-y3Veo0vwZfrIZxvwHYBjg5CpYRgCWghCQ,738
8
8
  account/migrations/0004_group_modified_alter_group_created.py,sha256=20iNFlUGtRCWUsxEqTJFRQKQ73z4REhfo-hGam8IHXY,551
@@ -22,9 +22,10 @@ account/migrations/0017_rename_requires_topt_member_requires_totp.py,sha256=GksG
22
22
  account/migrations/0018_userpasskey.py,sha256=SdXYo4TkIeP5wLNfCza3Jq5-gKuUufzTHGBw0hFQOMY,1475
23
23
  account/migrations/0019_group_location.py,sha256=EfMB_w4qWUGDqQeNc453PFZwpjpTeoA6xr6Qgo_YAOM,601
24
24
  account/migrations/0020_cloudcredentials_cloudcredentialsmetadata.py,sha256=mHwxkyDfA4ueQOt34w5ndJB4XwNTDLv79CkKgzhlz-c,2250
25
+ account/migrations/0021_alter_cloudcredentials_group.py,sha256=zoFYmE-hd3uRGX6DRO9k-osPwH0jFeTU7S-pjCOtakk,561
25
26
  account/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
27
  account/models/__init__.py,sha256=cV_lMnT2vL_mjiYtT4hlcIHo52ocFbGSNVkOIHHLXZY,385
27
- account/models/device.py,sha256=TloXvvrx3khF3BeGFuVYn6DhXjOW0AMZb4F9Fl5nBII,5491
28
+ account/models/device.py,sha256=dKq6fDQSKkeBrq9glZtmewSQPDBCnYuUlBEx7ZonfBc,5693
28
29
  account/models/feeds.py,sha256=vI7fG4ASY1M0Zjke24RdnfDcuWeATl_yR_25jPmT64g,2011
29
30
  account/models/group.py,sha256=mjWwePt3ogQUo9m0EhURMz0aBrVVx_0Drr0lNDESQio,22281
30
31
  account/models/legacy.py,sha256=zYdtv4LC0ooxPVqWM-uToPwV-lYWQLorSE6p6yn1xDw,2720
@@ -41,7 +42,7 @@ account/passkeys/core.py,sha256=xj-vXjSrfWDvc5MYtEmXzwaMkNHl-cXrQKVrN9soRCg,4126
41
42
  account/periodic.py,sha256=-u0n-7QTJgDOkasGhBAPwHAwjpqWGA-MZLEFkVTqCGU,874
42
43
  account/rpc/__init__.py,sha256=SGF0M_-H0dKh3b1apSX29BotNWAvITYccGQVC0MIjL8,336
43
44
  account/rpc/auth.py,sha256=p62tyihWvSY2zn7eaVxKcCG9qLnnZBIkwdRH81sS5_Y,16615
44
- account/rpc/device.py,sha256=mB14a6qvJIBnCa9ivLhPXwEt5Gk2foyqsKBtZxC506k,3070
45
+ account/rpc/device.py,sha256=lU2BHNPreHV0dDTjAPc7Sc-5m2JP8SiWVqiKuBfV7Fo,2281
45
46
  account/rpc/group.py,sha256=riymUK6ttv8G6SG6K-v7UCvM40WQy3HaGSeF_sEiaU0,4929
46
47
  account/rpc/member.py,sha256=VNRSD38mmTUCbq3cCSy3qRyquzeVEwW_8zzrtS0-vAA,1817
47
48
  account/rpc/notify.py,sha256=Q2YWejP36egeF060Hih5uX4Psv_B8NWlLLPi7iDYlIw,3344
@@ -479,7 +480,7 @@ wiki/migrations/0002_alter_pagemedia_entry.py,sha256=9CUnfvBmj0D4akCkux7HFuXgw9B
479
480
  wiki/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
480
481
  wiki/models/__init__.py,sha256=jE-9r_Hqpyo7ysKu9BschXOn5Zg34wUt894GwJpxA28,132
481
482
  wiki/models/faq.py,sha256=nvcEFerllQKT61kIYlasvZzRKwpXyfmQpiqkpHP1V1o,1745
482
- wiki/models/page.py,sha256=YLsuzYZZ8Vs1H8akwMrWxg6G7_EbRYp86tUry43hfnE,7203
483
+ wiki/models/page.py,sha256=7_HAbvHtWIQpttiMoxrm8-Mfik6kUW6F47xkXZN2Omk,7311
483
484
  wiki/models/revision.py,sha256=St5-vz8SGvogsDL6jTWqHLE23PS5mp9iA0DUt3hWTsU,729
484
485
  wiki/periodic.py,sha256=t-UgXJIug-OLslJM_r03-5WrNKj39TxrvfuNFjVAhDs,334
485
486
  wiki/renderers/__init__.py,sha256=lLEoJvjU3ezXwBGcjleKk_kMyNeMD9MpfBlEiKayEiM,461
@@ -491,7 +492,7 @@ wiki/renderers/mistune/meta.py,sha256=1lry9m-4wiwsivWnqYHYjwmGv91BGUSB7niJuZ1Xx5
491
492
  wiki/renderers/mistune/task_list.py,sha256=Ex0gUPX_d9jtbPbnEEktlqAJsM6wIt5Md2wsltX7LIY,1889
492
493
  wiki/renderers/mistune/toc.py,sha256=TKGiuMVpKqzDGUx5bAjJYpZIzG6n3wTjtuBdBc-TM_8,2302
493
494
  wiki/rpc/__init__.py,sha256=RgDYw5NSWxvx-VO3f9ONWNqhAgvec_4_IBfvZCsOR9I,40
494
- wiki/rpc/wiki.py,sha256=iWehZasU8J1E5sPPqz9QoQr3MpGxqu3rd7CH4wFrm2w,1333
495
+ wiki/rpc/wiki.py,sha256=RQY1gtqxdNhp13n3SkZL9WZ6RatrtCIh7QOYta6-UUU,1327
495
496
  wiki/tq.py,sha256=wvuBZ3OMV_D2o4kpJhVLIOwpEUfwlglqLJQvpncAwtk,313
496
497
  ws4redis/README.md,sha256=QvwdsauPKxx4qQqnJ991xeU8DgFQCj3CeQt-nCE4s-w,3624
497
498
  ws4redis/__init__.py,sha256=teNfv83A_ke1CBt9BB7NsnWCcFBhnUFPsPESjF554_k,46
@@ -506,7 +507,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
506
507
  ws4redis/settings.py,sha256=K0yBiLUuY81iDM4Yr-k8hbvjn5VVHu5zQhmMK8Dtz0s,1536
507
508
  ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
508
509
  ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
509
- django_restit-4.2.92.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
510
- django_restit-4.2.92.dist-info/METADATA,sha256=Cc0596dSa_nBz3E8F6ac6yxrVhzob92fIQzzqhiIc9Y,7645
511
- django_restit-4.2.92.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
512
- django_restit-4.2.92.dist-info/RECORD,,
510
+ django_restit-4.2.94.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
511
+ django_restit-4.2.94.dist-info/METADATA,sha256=OF5R_SKbBZBXK-wIkgj6rH4kFxWfRPnNQmSIVEoncqw,7662
512
+ django_restit-4.2.94.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
513
+ django_restit-4.2.94.dist-info/RECORD,,
wiki/models/page.py CHANGED
@@ -14,6 +14,7 @@ class Page(dm.Model, rm.RestModel, rm.MetaDataModel):
14
14
  SEARCH_FIELDS = ["title", "body"]
15
15
  SEARCH_TERMS = ["title", "body"]
16
16
  QUERY_FIELDS = ["all_fields", "parent__path"]
17
+ VIEW_PERMS = ["view_wiki", "edit_wiki"]
17
18
  UNIQUE_LOOKUP = ["path"]
18
19
  DEFAULT_SORT = "-order"
19
20
  CAN_DELETE = True
@@ -71,7 +72,7 @@ class Page(dm.Model, rm.RestModel, rm.MetaDataModel):
71
72
  }
72
73
  },
73
74
  "toc": {
74
- "extra": ["children"],
75
+ "extra": ["children", "metadata"],
75
76
  "graphs": {
76
77
  "self": "basic",
77
78
  "children": "toc_child"
@@ -205,6 +206,7 @@ class PageMetaData(rm.MetaDataBase):
205
206
 
206
207
  class PageMedia(dm.Model, rm.RestModel):
207
208
  class RestMeta:
209
+ VIEW_PERMS = ["view_wiki", "edit_wiki"]
208
210
  GRAPHS = {
209
211
  "basic": {
210
212
  "graphs": {
wiki/rpc/wiki.py CHANGED
@@ -5,14 +5,14 @@ from wiki import models as wiki
5
5
 
6
6
  @rd.url('page')
7
7
  @rd.url('page/<int:pk>')
8
- # @rd.login_required
8
+ @rd.login_required
9
9
  def rest_on_manage_wiki(request, pk=None):
10
10
  return wiki.Page.on_rest_request(request, pk)
11
11
 
12
12
 
13
13
  @rd.url('path')
14
14
  @rd.url('path/<path:path>')
15
- # @rd.login_required
15
+ @rd.login_required
16
16
  def rest_on_wiki(request, path=None):
17
17
  if path:
18
18
  entry = wiki.Page.objects.filter(path=path).last()
@@ -36,6 +36,6 @@ def rest_on_wiki(request, path=None):
36
36
 
37
37
  @rd.url('media')
38
38
  @rd.url('media/<int:pk>')
39
- # @rd.login_required
39
+ @rd.login_required
40
40
  def rest_on_wiki_media(request, pk=None):
41
41
  return wiki.PageMedia.on_rest_request(request, pk)
account/fcm/google.py DELETED
@@ -1,53 +0,0 @@
1
- import json
2
- import requests
3
- import time
4
- from jwt import JWT, jwk_from_dict
5
- from datetime import datetime, timedelta
6
-
7
-
8
- def oauthLogin(service_account_info):
9
- # Token endpoint
10
- token_uri = service_account_info["token_uri"]
11
-
12
- # The current time and expiration time for the assertion
13
- issued_at_time = datetime.utcnow()
14
- expiration_time = issued_at_time + timedelta(minutes=60)
15
-
16
- # JWT Header
17
- jwt_header = {
18
- "alg": "RS256",
19
- "typ": "JWT",
20
- "kid": service_account_info["private_key_id"]
21
- }
22
-
23
- # JWT Payload
24
- jwt_payload = {
25
- "iss": service_account_info["client_email"],
26
- "sub": service_account_info["client_email"],
27
- "aud": token_uri,
28
- "iat": int(issued_at_time.timestamp()),
29
- "exp": int(expiration_time.timestamp()),
30
- "scope": "https://www.googleapis.com/auth/firebase.messaging"
31
- }
32
-
33
- # Create a JWT
34
- jwt_instance = JWT()
35
- private_key = jwk_from_dict({"k": service_account_info["private_key"], "kty": "RSA"})
36
- assertion = jwt_instance.encode(jwt_header, jwt_payload, private_key)
37
-
38
- # Exchange the JWT for an access token
39
- response = requests.post(token_uri, data={
40
- "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
41
- "assertion": assertion
42
- })
43
-
44
- response_data = response.json()
45
-
46
- access_token = response_data.get("access_token")
47
- expires_in = response_data.get("expires_in") # Seconds until the token expires
48
-
49
- # You can now use this access_token to authenticate requests to Google APIs.
50
- # Remember to refresh the token using a similar process once it's close to expiration.
51
-
52
- print("Access Token:", access_token)
53
- print("Expires In:", expires_in)