Add CLI source code and update .gitignore
This commit is contained in:
115
cli_anything/codimd/core/user.py
Normal file
115
cli_anything/codimd/core/user.py
Normal file
@@ -0,0 +1,115 @@
|
||||
"""
|
||||
User operations for CodiMD CLI.
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
from .client import CodiMDClient
|
||||
|
||||
|
||||
class UserManager:
|
||||
"""Manager for user operations."""
|
||||
|
||||
def __init__(self, client: CodiMDClient):
|
||||
self.client = client
|
||||
|
||||
def login(self, email: str, password: str) -> Dict[str, Any]:
|
||||
"""Login with email and password.
|
||||
|
||||
Returns the session cookies and user info.
|
||||
"""
|
||||
# First, get the login page to obtain CSRF token if needed
|
||||
login_page = self.client.get("/login")
|
||||
|
||||
# Try to extract CSRF token from the page
|
||||
csrf_token = None
|
||||
csrf_match = re.search(r'name="csrf".*?value="([^"]+)"', login_page.text)
|
||||
if csrf_match:
|
||||
csrf_token = csrf_match.group(1)
|
||||
|
||||
# Prepare login data
|
||||
login_data = {
|
||||
"email": email,
|
||||
"password": password,
|
||||
}
|
||||
if csrf_token:
|
||||
login_data["_csrf"] = csrf_token
|
||||
|
||||
# Perform login
|
||||
response = self.client.post(
|
||||
"/login",
|
||||
data=login_data,
|
||||
allow_redirects=True
|
||||
)
|
||||
|
||||
# Check if login was successful by trying to access /me
|
||||
me_response = self.client.get("/me")
|
||||
if me_response.status_code == 200:
|
||||
user_data = me_response.json()
|
||||
return {
|
||||
"success": True,
|
||||
"user": user_data,
|
||||
"cookies": self.client.get_cookies()
|
||||
}
|
||||
|
||||
# Login failed
|
||||
if response.status_code == 302:
|
||||
# Redirect might indicate failure or success
|
||||
location = response.headers.get("Location", "")
|
||||
if "login" in location.lower():
|
||||
raise PermissionError("Login failed: Invalid credentials")
|
||||
return {
|
||||
"success": True,
|
||||
"cookies": self.client.get_cookies()
|
||||
}
|
||||
|
||||
raise PermissionError(f"Login failed: {response.status_code}")
|
||||
|
||||
def get_me(self) -> Dict[str, Any]:
|
||||
"""Get current user information."""
|
||||
response = self.client.get("/me")
|
||||
|
||||
if response.status_code == 403:
|
||||
raise PermissionError("Not authenticated")
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Failed to get user info: {response.status_code}")
|
||||
|
||||
return response.json()
|
||||
|
||||
def export_my_data(self) -> Dict[str, Any]:
|
||||
"""Export all user data."""
|
||||
response = self.client.post(
|
||||
"/me/export",
|
||||
data={},
|
||||
headers={"Content-Type": "application/x-www-form-urlencoded"}
|
||||
)
|
||||
|
||||
if response.status_code == 403:
|
||||
raise PermissionError("Not authenticated")
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Failed to export data: {response.status_code}")
|
||||
|
||||
return response.json()
|
||||
|
||||
def delete_user(self, delete_token: Optional[str] = None) -> bool:
|
||||
"""Delete current user account."""
|
||||
url = f"/me/delete/{delete_token}" if delete_token else "/me/delete"
|
||||
response = self.client.get(url)
|
||||
|
||||
if response.status_code == 403:
|
||||
raise PermissionError("Not authenticated or invalid token")
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Failed to delete user: {response.status_code}")
|
||||
|
||||
return True
|
||||
|
||||
def get_avatar(self, username: str) -> bytes:
|
||||
"""Get user avatar SVG."""
|
||||
response = self.client.get(f"/user/{username}/avatar.svg")
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Failed to get avatar: {response.status_code}")
|
||||
|
||||
return response.content
|
||||
Reference in New Issue
Block a user