Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin Update #1

Open
wants to merge 156 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
156 commits
Select commit Hold shift + click to select a range
f3d059d
create dataset
wajones98 Feb 8, 2024
e958ab0
document creation
wajones98 Feb 8, 2024
24efc85
remaining crud operations for documents
wajones98 Feb 8, 2024
2bb92e5
Fix documentRead
wajones98 Feb 8, 2024
5b39661
Authentication
wajones98 Feb 9, 2024
3a316a8
Add config
wajones98 Feb 9, 2024
be2b824
Load values from config
wajones98 Feb 13, 2024
51f801a
Move document create to falkor_client
wajones98 Feb 14, 2024
c9e9839
move delete and update to falkor_client
wajones98 Feb 14, 2024
b93865f
Move datasetCreate to falkor client
wajones98 Feb 14, 2024
943daba
remove task2 and fix create_dataset call
wajones98 Feb 14, 2024
b9e1dab
fix falkorDelete method name
wajones98 Feb 14, 2024
9e85a3a
Use config for remaining values
wajones98 Feb 16, 2024
d2b04f9
Add user_ids to audit events
wajones98 Feb 21, 2024
224ac92
Add audit button to resource button action panel
wajones98 Apr 9, 2024
30baa1e
Cleanup unused vars/imports
wajones98 Apr 9, 2024
e17148e
Render audit in table on the resource view page
wajones98 Apr 9, 2024
569aaca
Revert audit template to external link
wajones98 Apr 11, 2024
a51d1d3
Adjust position of audit button
wajones98 Apr 15, 2024
a6abfb3
Adjust audit url and add query params
wajones98 Apr 15, 2024
2c349a0
read audit base url from config
wajones98 Apr 18, 2024
225b78e
Org id handling refactor
wajones98 Apr 18, 2024
b39e33d
Move access token to job
wajones98 Oct 3, 2024
d19ff4b
Remove unused import
wajones98 Oct 4, 2024
f299bdf
Rename resource -> package
wajones98 Oct 4, 2024
b171e26
Log package activity stream
wajones98 Oct 4, 2024
b00b586
bug fix: move toolkit userobj access outside of worker
wajones98 Oct 7, 2024
bde1b76
Remove test log
wajones98 Oct 8, 2024
1c1c344
formatting
wajones98 Oct 8, 2024
4e87a6b
Create dataset_sync table and load with existing datasets
wajones98 Oct 8, 2024
6840355
Load dataset ids as part of migration
wajones98 Oct 8, 2024
3c8a631
Use resource model instead of dict
wajones98 Oct 8, 2024
96c8d7d
Log event to table
wajones98 Oct 9, 2024
e3d9b27
Test custom_action
wajones98 Oct 10, 2024
d4cce71
New EventHandler class
wajones98 Oct 10, 2024
88ba7ac
Refactor events to event_handler
wajones98 Oct 15, 2024
bf3a6c3
Rename falkor_client -> client
wajones98 Oct 15, 2024
c8a4a9e
Temporarily remove actions plugin
wajones98 Oct 15, 2024
3bd1df6
Add event type to event_handler
wajones98 Oct 15, 2024
31edc47
Improve package create event
wajones98 Oct 15, 2024
2d3b5c3
Add TODO
wajones98 Oct 15, 2024
731934d
Add todo and check resource state before logging event
wajones98 Oct 15, 2024
437f6c4
Capture resource events
wajones98 Oct 15, 2024
b2e29bf
Add seq to read events
wajones98 Oct 17, 2024
a0af9ef
Add some TODOS and clean up comments
wajones98 Oct 17, 2024
af370fd
Remove event sequence
wajones98 Oct 21, 2024
691f9cd
config migration
wajones98 Oct 21, 2024
213dbcf
Remove sequence from event model
wajones98 Oct 21, 2024
69fd68a
Move event processing back to worker
wajones98 Oct 21, 2024
5aee350
Check plugin is initialised before tracking events
wajones98 Oct 22, 2024
26380b2
Validate config on plugin startup
wajones98 Oct 22, 2024
2cf4d47
initialise plugin function
wajones98 Oct 22, 2024
0662a0f
Remove falkor config table and introduce sync job
wajones98 Oct 22, 2024
83307ce
Add migration for sync job history
wajones98 Oct 22, 2024
32d79d4
insert sync job
wajones98 Oct 22, 2024
8fee68a
Refactor package_create to reprocess events
wajones98 Oct 22, 2024
668983f
Make event_handler handlers compatible with sync job
wajones98 Oct 23, 2024
f72c20f
Simplify event handling
wajones98 Oct 23, 2024
06e40b4
Remove sync job run in plugin startup
wajones98 Oct 23, 2024
1cb9dc6
Remove unused plugin properties
wajones98 Oct 23, 2024
e919d1d
Add processing status to events
wajones98 Oct 23, 2024
bc70d70
Change event_handler to class
wajones98 Oct 23, 2024
1dbb1d1
Add timeout to auth post requests
wajones98 Oct 23, 2024
00939c7
Add return type to falkor api requests
wajones98 Oct 23, 2024
79ba78c
Reintroduce package create events for falkor
wajones98 Oct 23, 2024
bef3be7
Do not process resources that still have a pending create package event
wajones98 Oct 23, 2024
e253b8f
Events for new documents
wajones98 Oct 24, 2024
5be0bd9
Add events for existing documents
wajones98 Oct 24, 2024
417dbf8
Move processing location and remove response() from exception
wajones98 Oct 24, 2024
e1cc8dc
Pass entity to event handler and fix created_at
wajones98 Oct 24, 2024
ded98c2
Remove created_at from before_show
wajones98 Oct 24, 2024
5ada201
Update temp read filter to use regex
wajones98 Oct 24, 2024
50f1363
Reintroduce dict and org id
wajones98 Oct 24, 2024
cde1a98
Add entity to sync jobs
wajones98 Oct 28, 2024
22997e7
Add admin tab
wajones98 Oct 28, 2024
c9ed66d
Properly inheirt admin page
wajones98 Oct 28, 2024
be41028
Start sync job from admin button
wajones98 Oct 28, 2024
f6edacf
UI for Falkor admin tab
wajones98 Oct 29, 2024
590fc25
Add order by to failed events
wajones98 Oct 29, 2024
548c992
Refactor metadata
wajones98 Oct 30, 2024
aacb15d
Remove defaults for job id and start from new sync job
wajones98 Oct 31, 2024
ab9c614
Add job ID to sync job exception message
wajones98 Oct 31, 2024
02ace03
Add event ID to event processing exception
wajones98 Oct 31, 2024
0f8e4e9
Add reprocess button for failed events
wajones98 Oct 31, 2024
49b3099
Remove TODOs and only sync unique events
wajones98 Oct 31, 2024
137c3d1
Check resource id in request url
wajones98 Nov 1, 2024
e026453
Add sysadmin check to reprocessing jobs
wajones98 Nov 1, 2024
3c15e25
Check sysadmin role for plugin endpoints
wajones98 Nov 12, 2024
13c5e63
Update FalkorEvent
wajones98 Nov 19, 2024
c3d7a22
Replace FalkorEventObjectType
wajones98 Nov 19, 2024
ca5af33
Update FalkorEvent model and remove get_package_without_create_events…
wajones98 Nov 19, 2024
5556e18
notify refactor
wajones98 Nov 19, 2024
84fe580
remove object_id and type from FalkorEvent in before_show
wajones98 Nov 19, 2024
dfa394e
Change instance check to elif
wajones98 Nov 19, 2024
a1ae957
Remove create packages without create events for sync
wajones98 Nov 19, 2024
ff53b8e
Refactor client
wajones98 Nov 19, 2024
d4e3aff
Import HttpError from requests
wajones98 Nov 19, 2024
78ad6f5
Remove old object type filter from get resources func
wajones98 Nov 19, 2024
ba905e7
get_dictized_entity -> get_dictized_resource
wajones98 Nov 19, 2024
ffc0398
Remove package import from model
wajones98 Nov 19, 2024
ab01073
New job queue name enum
wajones98 Nov 19, 2024
b69121e
Remove Union import from model
wajones98 Nov 19, 2024
9837be8
Remove FalkorEventObjectType import
wajones98 Nov 19, 2024
3b245fd
Capitalise names for FalkorEventResourceType Enum
wajones98 Nov 19, 2024
c468035
refactor handle to handle_event
wajones98 Nov 19, 2024
49122ff
Remove package_create_event_for_resource
wajones98 Nov 19, 2024
4399449
Move CONTEXT to model as TOOLKIT_CONTEXT
wajones98 Nov 19, 2024
c532bb0
Rename CONTEXT to TOOLKIT_CONTEXT in plugin
wajones98 Nov 19, 2024
70eaee3
Add create_new_event function
wajones98 Nov 19, 2024
5210845
Simplify event handling
wajones98 Nov 19, 2024
0a5a3b5
Handle stream resource types
wajones98 Nov 19, 2024
01a4230
Add ckan.model import
wajones98 Nov 19, 2024
8df4c8a
Fix ResourceType enum for migration
wajones98 Nov 19, 2024
5b6ee2d
comment out funcs to refactor
wajones98 Nov 19, 2024
71aa410
Fix name for resourceType in migration
wajones98 Nov 19, 2024
256090f
QUery db directly to avoid recursive calls to "package_show"
wajones98 Nov 19, 2024
9f5bc7d
Get package and org directly from db
wajones98 Nov 19, 2024
2f89201
Remove debug line for org
wajones98 Nov 19, 2024
c9895cf
Fix typo for HTTPError exception
wajones98 Nov 19, 2024
e206f1c
Return result from create_new_event
wajones98 Nov 19, 2024
e844f02
Add missing status column to FalkorEvent
wajones98 Nov 19, 2024
0d08da7
Remove commit before setting event status
wajones98 Nov 19, 2024
f837016
formatting
wajones98 Nov 19, 2024
472773b
Remove queue name for now
wajones98 Nov 19, 2024
3db146a
formatting
wajones98 Nov 19, 2024
3a73989
convert document events to json
wajones98 Nov 19, 2024
115c306
parse datetime from string
wajones98 Nov 19, 2024
8361a0c
Fix issues with parsing document body json
wajones98 Nov 19, 2024
9cae957
Just use datetime.now for updated event
wajones98 Nov 20, 2024
2428fe0
Update admin template with new FalkorEvent model
wajones98 Nov 20, 2024
f65988b
Make reprocessing single event synchronous
wajones98 Nov 20, 2024
f9da529
Reprocess all button
wajones98 Nov 20, 2024
b13132c
Reintroduce sync job with latest changes
wajones98 Nov 20, 2024
a835535
Add retries to falkor calls
wajones98 Nov 20, 2024
69a8b41
ADd commit to add a "running" sync job
wajones98 Nov 20, 2024
81bcd34
Remove unused imports
wajones98 Nov 20, 2024
673f490
Remove job queue name
wajones98 Nov 20, 2024
7874cd5
Remove unused code
wajones98 Nov 20, 2024
06b9d96
Remove outdated TODO
wajones98 Nov 20, 2024
33deeeb
Remove org id from audit path
wajones98 Nov 20, 2024
3633e42
refactor audit url
wajones98 Nov 20, 2024
83b8159
Fix bug with setting resource_id for stream type and add resource typ…
wajones98 Nov 20, 2024
3df89af
get raw value from resource type for metadata
wajones98 Nov 20, 2024
6ca5130
Handle session from within get_event func
wajones98 Nov 20, 2024
e577bfe
Use get_events with filter input instead of separate functiosn for ea…
wajones98 Nov 20, 2024
2e99afb
Add tabs for event statuses to falkor admin tab
wajones98 Nov 20, 2024
c33457c
Properly construct audit url based off of resource type
wajones98 Nov 20, 2024
79565d4
Check event_status query value
wajones98 Nov 20, 2024
a164dcc
Remove debug log
wajones98 Nov 21, 2024
9c10c9d
Rename parameters in falkor client methods
wajones98 Nov 21, 2024
f96f584
Remove unused func
wajones98 Nov 21, 2024
a909ab8
Check resource_type is not None
wajones98 Nov 21, 2024
6de11ab
Adjust comment
wajones98 Nov 21, 2024
2672d0c
Add support for all event statuses to reprocess_all
wajones98 Nov 21, 2024
034d06c
Add more logs for debugging
wajones98 Nov 21, 2024
dd024c1
Fix url for reprocessing a single event
wajones98 Nov 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions ckanext/falkor/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import logging
import requests
import time
from typing import Union

log = logging.getLogger(__name__)


class Credentials:
client_id: str
client_secret: str
username: str
password: str

def __init__(
self, client_id: str, client_secret: str, username: str, password: str
):
self.client_id = client_id
self.client_secret = client_secret
self.username = username
self.password = password


class Token:
token: str
expires_in: int

def __init__(self, token: str, expires_in: int):
self.token = token
self.expires_in = expires_in


class Auth:
__access_token: Union[Token, None]
__refresh_token: Union[Token, None]
__credentials: Credentials
__timestamp: float
__endpoint: str

def __init__(self, credentials: Credentials, endpoint: str):
self.__credentials = credentials
self.__access_token = None
self.__refresh_token = None
self.__timestamp = 0
self.__endpoint = endpoint

@property
def access_token(self) -> str:
if self.__access_token is None or self.__refresh_token is None:
log.debug("No tokens, logging in...")
self.__login()
elif self.__is_token_expired(self.__refresh_token):
log.debug("Refresh token expired, reauthenticating...")
self.__login()
elif self.__is_token_expired(self.__access_token):
log.debug("Access token expired, refreshing...")
self.__refresh()
return self.__access_token.token

def __is_token_expired(self, token: Token) -> bool:
expires_at = self.__timestamp + token.expires_in
current_time = time.time()
return current_time >= expires_at

def __login(self) -> None:
request = {
"client_id": self.__credentials.client_id,
"client_secret": self.__credentials.client_secret,
"username": self.__credentials.username,
"password": self.__credentials.password,
"grant_type": "password",
}
response = requests.post(self.__endpoint, request, timeout=10)
body = response.json()
self.__set_token(body)

def __refresh(self) -> None:
request = {
"grant_type": "refresh_token",
"client_id": self.__credentials.client_id,
"client_secret": self.__credentials.client_secret,
"refresh_token": self.__refresh_token.token,
}

response = requests.post(self.__endpoint, request, timeout=10)
body = response.json()
self.__set_token(body)

def __set_token(self, body) -> None:
self.__access_token = Token(body["access_token"], body["expires_in"])
self.__refresh_token = Token(
body["refresh_token"], body["refresh_expires_in"])
self.__timestamp = time.time()
201 changes: 201 additions & 0 deletions ckanext/falkor/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import requests
import logging
import json

from typing import TypedDict
from ckanext.falkor import auth
from requests import HTTPError, Session
from requests.adapters import HTTPAdapter, Retry

log = logging.getLogger(__name__)

HttpHeaders = TypedDict(
"HttpHeaders", {"Content-Type": str, "accept": str, "Authorization": str}
)


def base_headers(access_token: str) -> HttpHeaders:
return {
"Content-Type": "application/json",
"accept": "application/json",
"Authorization": "Bearer " + access_token,
}


def falkor_post(
session: Session,
url: str,
payload: dict,
auth: auth.Auth,
) -> requests.Response:
response = session.post(url, headers=base_headers(
auth.access_token), json=payload, timeout=120)
log.debug(response.json())
return response


def falkor_put(
session: Session,
url: str,
payload: dict,
auth: auth.Auth,
) -> requests.Response:
response = session.put(url, headers=base_headers(
auth.access_token), json=payload, timeout=120)
log.debug(response.json())
return response


def falkor_get(
session: Session,
url: str,
auth: auth.Auth,
) -> requests.Response:
response = session.get(url, headers=base_headers(
auth.access_token), timeout=120)
log.debug(response.json())
return response


def falkor_delete(
session: Session,
url: str,
auth: auth.Auth,
) -> requests.Response:
response = session.delete(url, headers=base_headers(
auth.access_token), timeout=120)
log.debug(response.json())
return response


class Client:
__auth: auth.Auth
__core_base_url: str
__admin_base_url: str
__tenant_id: str
__http_session: Session

def __init__(
self,
auth: auth.Auth,
tenant_id: str,
core_base_url: str,
admin_base_url: str
):
self.__auth = auth
self.__tenant_id = tenant_id
self.__core_base_url = core_base_url
self.__admin_base_url = admin_base_url

http_session = requests.Session()
retries = Retry(total=5,
backoff_factor=0.1,
status_forcelist=[500, 502, 503, 504])
http_session.mount(
self.__core_base_url, HTTPAdapter(max_retries=retries))
http_session.mount(
self.__admin_base_url, HTTPAdapter(max_retries=retries))

self.__http_session = http_session

def dataset_create(self, dataset_id: str):
url = self.__admin_base_url + self.__tenant_id + "/dataset"
payload = {
"datasetId": dataset_id,
"encryptionType": "none",
"externalStorage": "false",
"permissionEnabled": "false",
"taggingEnabled": "false",
"iotaEnabled": "false",
"tokensEnabled": "false",
}

falkor_post(self.__http_session, url, payload,
self.__auth).raise_for_status()

def dataset_exists(self, dataset_id: str) -> bool:
url = self.__core_base_url + self.__tenant_id + "/dataset/" + dataset_id + "/info"
try:
falkor_get(self.__http_session, url,
self.__auth).raise_for_status()
return True
except HTTPError as e:
if e.response.status_code == 404:
return False
else:
log.exception(e)
raise e

def document_exists(self, dataset_id: str, document_id: str) -> bool:
url = self.__core_base_url + self.__tenant_id + \
"/dataset/" + dataset_id + "/" + document_id + "/info"
try:
falkor_get(self.__http_session, url,
self.__auth).raise_for_status()
return True
except HTTPError as e:
if e.response.status_code == 404:
return False
else:
log.exception(e)
raise e

def document_get(self, dataset_id: str, document_id: str):
url = (
self.__core_base_url
+ self.__tenant_id
+ "/dataset/"
+ dataset_id
+ "/"
+ document_id
+ "/body"
)

resp = falkor_get(self.__http_session, url, self.__auth)
resp.raise_for_status()
return resp.json()

def document_create(
self,
dataset_id: str,
document_id: str,
data: str,
metadata: dict,
):

url = (
self.__core_base_url
+ self.__tenant_id
+ "/dataset/"
+ dataset_id
+ "/create"
)
payload = {
"documentId": document_id,
"data": json.dumps(data),
"documentMetadata": metadata,
}
log.debug(f"Creating document with payload:\n {payload}")

falkor_post(self.__http_session, url, payload,
self.__auth).raise_for_status()

def document_update(
self,
dataset_id: str,
document_id: str,
data: str
):
url = (
self.__core_base_url
+ self.__tenant_id
+ "/dataset/"
+ dataset_id
+ "/"
+ document_id
+ "/body"
)
log.debug(f"Updating document with payload:\n {data}")

falkor_put(self.__http_session, url, data,
self.__auth).raise_for_status()
Loading