a proper project@
This commit is contained in:
commit
bb0474fe07
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
**/__pycache__/
|
||||||
|
.venv/
|
||||||
|
.idea/
|
||||||
|
keys/
|
||||||
|
poetry.lock
|
20
examples/check-key.py
Normal file
20
examples/check-key.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
host = 'forum.lunduke.com'
|
||||||
|
username = 'gmgauthier'
|
||||||
|
url = f"https://{host}/posts.json"
|
||||||
|
|
||||||
|
|
||||||
|
with open('../keys/cli_key.txt', 'r') as key:
|
||||||
|
api_key = key.read()
|
||||||
|
api_key = api_key.replace('\n', '').replace('\r', '')
|
||||||
|
|
||||||
|
|
||||||
|
headers={
|
||||||
|
"api_key": api_key,
|
||||||
|
"api_username": username
|
||||||
|
}
|
||||||
|
response = requests.get(url,headers=headers)
|
||||||
|
print(response.status_code)
|
||||||
|
print(response.json())
|
34
examples/example.py
Normal file
34
examples/example.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
from lunduke.config import DiscourseConfig
|
||||||
|
from lunduke.auth import DiscourseAuth
|
||||||
|
from lunduke.client import DiscourseClient
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Set up configuration
|
||||||
|
config = DiscourseConfig(
|
||||||
|
host='forum.lunduke.com',
|
||||||
|
username='gmgauthier'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set up authentication
|
||||||
|
auth = DiscourseAuth(
|
||||||
|
api_key_file='../keys/cli_key.txt',
|
||||||
|
username=config.username
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create client
|
||||||
|
client = DiscourseClient(config, auth)
|
||||||
|
|
||||||
|
# Use the client
|
||||||
|
try:
|
||||||
|
response = client.get('/posts.json')
|
||||||
|
posts = response['latest_posts']
|
||||||
|
print(f"Found {len(posts)} posts")
|
||||||
|
for post in posts:
|
||||||
|
print(post['post_type'], post['username'], post['topic_id'])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
0
lunduke/__init__.py
Normal file
0
lunduke/__init__.py
Normal file
34
lunduke/auth.py
Normal file
34
lunduke/auth.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
class DiscourseAuth:
|
||||||
|
"""Handles authentication with the Discourse API."""
|
||||||
|
|
||||||
|
def __init__(self, api_key=None, api_key_file=None, username=None):
|
||||||
|
"""
|
||||||
|
Initialize with API key details.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
api_key: The API key as a string
|
||||||
|
api_key_file: Path to file containing the API key
|
||||||
|
username: The API username
|
||||||
|
"""
|
||||||
|
self.username = username
|
||||||
|
self.api_key = None
|
||||||
|
|
||||||
|
if api_key:
|
||||||
|
self.api_key = api_key
|
||||||
|
elif api_key_file:
|
||||||
|
self._load_key_from_file(api_key_file)
|
||||||
|
|
||||||
|
def _load_key_from_file(self, key_file):
|
||||||
|
"""Load API key from file and clean it."""
|
||||||
|
with open(key_file, 'r') as f:
|
||||||
|
self.api_key = f.read().strip().replace('\n', '').replace('\r', '')
|
||||||
|
|
||||||
|
def get_headers(self):
|
||||||
|
"""Return headers for API requests."""
|
||||||
|
if not self.api_key or not self.username:
|
||||||
|
raise ValueError("API key and username must be set")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"api_key": self.api_key,
|
||||||
|
"api_username": self.username
|
||||||
|
}
|
41
lunduke/client.py
Normal file
41
lunduke/client.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from lunduke.config import DiscourseConfig
|
||||||
|
from lunduke.auth import DiscourseAuth
|
||||||
|
|
||||||
|
|
||||||
|
class DiscourseClient:
|
||||||
|
"""Main client for interacting with the Discourse API."""
|
||||||
|
|
||||||
|
def __init__(self, config, auth):
|
||||||
|
"""
|
||||||
|
Initialize with configuration and authentication.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: DiscourseConfig instance
|
||||||
|
auth: DiscourseAuth instance
|
||||||
|
"""
|
||||||
|
self.config = config
|
||||||
|
self.auth = auth
|
||||||
|
self.session = requests.Session()
|
||||||
|
|
||||||
|
def get(self, endpoint, params=None) -> dict:
|
||||||
|
"""
|
||||||
|
Make a GET request to the API.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
endpoint: API endpoint (e.g., '/posts.json')
|
||||||
|
params: Optional query parameters
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Response data as JSON
|
||||||
|
"""
|
||||||
|
url = f"{self.config.get_base_url()}{endpoint}"
|
||||||
|
headers = self.auth.get_headers()
|
||||||
|
|
||||||
|
response = self.session.get(url, headers=headers, params=params)
|
||||||
|
response.raise_for_status() # Raise exception for error status codes
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
# Add other HTTP methods as needed (post, put, delete)
|
27
lunduke/config.py
Normal file
27
lunduke/config.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
class DiscourseConfig:
|
||||||
|
"""Configuration settings for the Discourse API client."""
|
||||||
|
|
||||||
|
def __init__(self, host, username=None, config_file=None):
|
||||||
|
"""
|
||||||
|
Initialize configuration with host and optional username.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
host: The Discourse forum host (e.g., 'forum.lunduke.com')
|
||||||
|
username: The API username
|
||||||
|
config_file: Optional path to a config file
|
||||||
|
"""
|
||||||
|
self.host = host
|
||||||
|
self.username = username
|
||||||
|
self.api_url = f"https://{host}"
|
||||||
|
|
||||||
|
if config_file:
|
||||||
|
self._load_from_file(config_file)
|
||||||
|
|
||||||
|
def _load_from_file(self, config_file):
|
||||||
|
"""Load configuration from a file (JSON/YAML)."""
|
||||||
|
# Implementation for loading config from file
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_base_url(self):
|
||||||
|
"""Return the base URL for API requests."""
|
||||||
|
return self.api_url
|
0
lunduke/endpoints/__init__.py
Normal file
0
lunduke/endpoints/__init__.py
Normal file
0
lunduke/endpoints/posts.py
Normal file
0
lunduke/endpoints/posts.py
Normal file
0
lunduke/endpoints/users.py
Normal file
0
lunduke/endpoints/users.py
Normal file
17
pyproject.toml
Normal file
17
pyproject.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[project]
|
||||||
|
name = "lunduke-cli"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "An API client for the Lunduke Discourse server"
|
||||||
|
authors = [
|
||||||
|
{name = "Greg Gauthier",email = "gmgauthier@protonmail.com"}
|
||||||
|
]
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = [
|
||||||
|
"requests (>=2.32.3,<3.0.0)"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
36
scripts/keycheck.sh
Executable file
36
scripts/keycheck.sh
Executable file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env zsh
|
||||||
|
#
|
||||||
|
|
||||||
|
export AUTH_STRING = "QpklK0BfIbAZJogoY+sNAZHhch29o7wq4G4vBlAr3XRh7cAISzsW0cALv/b/vFGykw34CRDL8xJoX5vHZHKSe6ulOP3aQytrQAMlYRsO08Lp2otz0U8j+f3zL09bHQwASvCDJeJtUrg5cupTHkjQZR2x6AOO69b4VVppBhponcnE9wpb5wHB0kK0sBsDQEKN4G3rb/MiTT9/TgOshRo2/g6VZ7jYQt/dxDQnmoecWlPaAG0wVV3VOkRF3ZxxML7jZPDl/tN6PGwSEEWnctqkzmLVOcl/kq+6sLTA/bkoA7y9x6T5W7jjqNaSPA2/r0gBjy7WnCrZ5qDFHO8BTvvaHQ=="
|
||||||
|
|
||||||
|
export INKEY = "-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCz2JQg/0hMaFZR
|
||||||
|
DVm6vobNpgS8bH9nxH0neGE3Tmb3A3vFGgaWnFSoFsQlMu323vXQxfP+PVID4A10
|
||||||
|
HAYihadlc0fdP5LgNTBYkkG2ena4ci9m52cRu/lE0MvFigyQJ2LZGg16F7Elz3I0
|
||||||
|
KmMdcA++Yqb7nLD3otqF6Y4/T/HVaSw8hVSI+RI98haPSo/UDxSBlGw+Hi8XUiwd
|
||||||
|
Qsrbn5BCh1UN+Wb/gUa2NnmGg8oH0jCdEb7JzB+XTXlmhNMQjHUhn6fwBbacNcD4
|
||||||
|
9cQBK9GiJ1Hk5QLbHyWDF8wdFH6WTcQYPBt2kz/MknWEgw0dNGLhmB12YQrXj4mE
|
||||||
|
qFSiatqZAgMBAAECggEAIPkKw3f6WePhO2/+rQHEdkzDXoZn328DYSqtbDXoI86U
|
||||||
|
MSFh5tgXn0+5O3a4cUQUfmfkoY69jC9WWBzRNSAa/jsiCFrhA1FNIVgDS0Dtpkht
|
||||||
|
D2lKmNJFU8wSKA/02LMX6OThZqqUVHHRpuXEkT+b61Rr+AKU4XoOpXGaHlp6ZJ1a
|
||||||
|
MBhUkhGttZ8aHz64p/MtqhCttAFdBPkwkhKlll/ABs9qvnF1fifhm+RBqni0m3Xg
|
||||||
|
6yTmo2JYMX7QnzfXjdxwq5h8DkG9bdWuhTsWQB7AX1M3TJrsHRUWISTTP972V3/F
|
||||||
|
gshj1zfqRWWIEhiGE647PZxy1VdPOF1jASQtD4g2JwKBgQDsH11dbEdSiXtKkiu/
|
||||||
|
ndWrdQhtk8WbFl/nN39rXO7oMQlAKX0W89TY5n+PGZrxDQnlNg5a4jbzOI4QPvud
|
||||||
|
W19fEAUzsYoqb5LjjsYgbAwNdnjZiiv4ox2bt5taO7MCMH9q80GKtaUCH+m1A0bA
|
||||||
|
Y4Z3b4rl6WohqmOGKK6bi+pHZwKBgQDC/Gif+TRF4e9GqQTdba0ZNgArb4enHlVR
|
||||||
|
pLj47aIFg6vrf5D4U74+4Sf8BOhw6yIybnamEFHd2deECqrYizFxTKufkzAvV+Ux
|
||||||
|
Z3ehuXjFgCg9qSJW2FP3R9Ew5Lthmz/P5uKVR2AhoR2auhaNgw4rnzoAxGjqvRyZ
|
||||||
|
5RiJnTaN/wKBgHU7FUW+7qJB896QN/xIxr77uhV9WoynTTIk0bRiTZMmVWtvrdVp
|
||||||
|
dfHCbu6DTfQD/ze34OSqj5GuMIpMWuxDY1R1Rb/mk6yB/LHSPvf17P36JgILoc0u
|
||||||
|
XxLi09S28ydRINHeuFm/2Y72fTgLymLWhvphfNqtSq4wRH1lUVuU2dpdAoGAMTgD
|
||||||
|
tPXz4vwAKUb66mYH/sgpzM0PYfj/MmexJWzerCOrnvuJfZWt/TNao3wdrHs+G5rU
|
||||||
|
qmCOOcEGbNdAfv7L0Ty4ScSesiSuvwTOJu2pdbk+7ymleGSM9WuUe5IRVrcYqYMv
|
||||||
|
iN0GgBaqYWc90CTXy90aiB0MGsz3zkUNJ5eesMMCgYBuWT8Dqcm7EilaaRjwZkny
|
||||||
|
UENTDIsovLtJpZyhfXgMmGeYwAdJ8RldOM7KwL/jhVWgKTaZa68rhmp2/+q7Rb0M
|
||||||
|
YZiE9JdCUlXWOuQ7g7lynMEgWV7ctt6pDibUCaxgvel7UugbhqpM/UYW1RxC6caC
|
||||||
|
ZOGCjowKexE+WdZqwm0elQ==
|
||||||
|
-----END PRIVATE KEY-----"
|
||||||
|
|
||||||
|
echo "${AUTH_STRING}" | openssl enc -d -a | openssl pkeyutl -decrypt -inkey "${INKEY}" | cat
|
||||||
|
|
Loading…
Reference in New Issue
Block a user