a proper project@

This commit is contained in:
Greg Gauthier 2025-04-11 22:46:02 +01:00
commit bb0474fe07
12 changed files with 214 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
**/__pycache__/
.venv/
.idea/
keys/
poetry.lock

20
examples/check-key.py Normal file
View 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
View 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
View File

34
lunduke/auth.py Normal file
View 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
View 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
View 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

View File

View File

View File

17
pyproject.toml Normal file
View 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
View 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