Post-Local sync at 2025-06-23T22:46:07Z
This commit is contained in:
parent
9d33b42020
commit
9f97801b0d
1387 changed files with 250216 additions and 117 deletions
269
.venv/lib/python3.12/site-packages/internetarchive/account.py
Normal file
269
.venv/lib/python3.12/site-packages/internetarchive/account.py
Normal file
|
@ -0,0 +1,269 @@
|
|||
import json
|
||||
from dataclasses import dataclass, field
|
||||
from typing import ClassVar, Dict, List, Optional
|
||||
|
||||
import requests
|
||||
|
||||
from internetarchive import get_session
|
||||
from internetarchive.exceptions import AccountAPIError
|
||||
from internetarchive.session import ArchiveSession
|
||||
|
||||
"""
|
||||
internetarchive.account
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: (C) 2012-2025 by Internet Archive.
|
||||
:license: AGPL 3, see LICENSE for more details.
|
||||
|
||||
This module provides the `Account` class for interacting with user accounts on the
|
||||
Internet Archive. It requires administrative privileges.
|
||||
"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Account:
|
||||
"""
|
||||
A class for interacting with user accounts on the Internet Archive.
|
||||
|
||||
Note:
|
||||
This class requires administrative privileges.
|
||||
|
||||
This class provides methods to:
|
||||
- Fetch account details using various identifiers (e.g., email, screenname, itemname).
|
||||
- Lock and unlock accounts.
|
||||
- Convert account data to a dictionary for serialization.
|
||||
|
||||
Example Usage:
|
||||
>>> from internetarchive.account import Account
|
||||
>>> account = Account.from_account_lookup('email', 'foo@example.com')
|
||||
>>> account.lock(comment="Locked spam account")
|
||||
>>> print(account.to_dict())
|
||||
"""
|
||||
locked: bool
|
||||
verified: bool
|
||||
email: str
|
||||
canonical_email: str
|
||||
itemname: str
|
||||
screenname: str
|
||||
notifications: List[str]
|
||||
has_disability_access: bool
|
||||
lastlogin: str
|
||||
createdate: str
|
||||
session: ArchiveSession = field(default_factory=get_session)
|
||||
|
||||
API_BASE_URL: str = '/services/xauthn/'
|
||||
API_INFO_PARAMS: ClassVar[Dict[str, str]] = {'op': 'info'}
|
||||
API_LOCK_UNLOCK_PARAMS: ClassVar[Dict[str, str]] = {'op': 'lock_unlock'}
|
||||
|
||||
def _get_api_base_url(self) -> str:
|
||||
"""Dynamically construct the API base URL using the session's host."""
|
||||
return f'https://{self.session.host}{self.API_BASE_URL}' # type: ignore[attr-defined]
|
||||
|
||||
def _post_api_request(
|
||||
self,
|
||||
endpoint: str,
|
||||
params: Dict[str, str],
|
||||
data: Dict[str, str],
|
||||
session: Optional[ArchiveSession] = None
|
||||
) -> requests.Response:
|
||||
"""
|
||||
Helper method to make API requests.
|
||||
|
||||
Args:
|
||||
endpoint: The API endpoint to call.
|
||||
params: Query parameters for the request.
|
||||
data: Data to send in the request body.
|
||||
session: Optional session to use for the request. Defaults to self.session.
|
||||
|
||||
Returns:
|
||||
The response from the API.
|
||||
|
||||
Raises:
|
||||
requests.exceptions.RequestException: If the API request fails.
|
||||
"""
|
||||
session = session or self.session
|
||||
url = f'https://{session.host}{endpoint}' # type: ignore[attr-defined]
|
||||
response = session.post(url, params=params, data=data)
|
||||
response.raise_for_status()
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def from_account_lookup(
|
||||
cls,
|
||||
identifier_type: str,
|
||||
identifier: str,
|
||||
session: Optional[ArchiveSession] = None
|
||||
) -> "Account":
|
||||
"""
|
||||
Factory method to initialize an Account using an identifier type and value.
|
||||
|
||||
Args:
|
||||
identifier_type: The type of identifier (e.g., 'email', 'screenname').
|
||||
identifier: The value of the identifier (e.g., 'foo@example.com').
|
||||
session: Optional session to use for the request.
|
||||
|
||||
Returns:
|
||||
An instance of Account.
|
||||
"""
|
||||
json_data = cls._fetch_account_data_from_api(identifier_type, identifier, session)
|
||||
return cls.from_json(json_data, session)
|
||||
|
||||
@classmethod
|
||||
def _fetch_account_data_from_api(
|
||||
cls,
|
||||
identifier_type: str,
|
||||
identifier: str,
|
||||
session: Optional[ArchiveSession] = None
|
||||
) -> Dict:
|
||||
"""
|
||||
Fetches account data from the API using an identifier type and value.
|
||||
|
||||
Args:
|
||||
identifier_type: The type of identifier (e.g., 'email', 'screenname').
|
||||
identifier: The value of the identifier (e.g., 'foo@example.com').
|
||||
session: Optional session to use for the request.
|
||||
|
||||
Returns:
|
||||
A dictionary containing the account data.
|
||||
|
||||
Raises:
|
||||
requests.exceptions.RequestException: If the API request fails.
|
||||
ValueError: If the API response is invalid or missing required data.
|
||||
"""
|
||||
data = {identifier_type: identifier}
|
||||
session = session or get_session()
|
||||
try:
|
||||
response = session.post(
|
||||
f'https://{session.host}{cls.API_BASE_URL}', # type: ignore[attr-defined]
|
||||
params=cls.API_INFO_PARAMS,
|
||||
data=json.dumps(data)
|
||||
)
|
||||
response.raise_for_status()
|
||||
j = response.json()
|
||||
if j.get("error") or not j.get("values"):
|
||||
raise AccountAPIError(j.get("error", "Unknown error"), error_data=j)
|
||||
return j["values"]
|
||||
except requests.exceptions.RequestException as e:
|
||||
raise AccountAPIError(f"Failed to fetch account data: {e}")
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_json(
|
||||
cls,
|
||||
json_data: Dict,
|
||||
session: Optional[ArchiveSession] = None
|
||||
) -> "Account":
|
||||
"""
|
||||
Factory method to initialize an Account using JSON data.
|
||||
|
||||
Args:
|
||||
json_data: A dictionary containing account data.
|
||||
session: Optional session to use for the request.
|
||||
|
||||
Returns:
|
||||
An instance of Account.
|
||||
|
||||
Raises:
|
||||
ValueError: If required fields are missing in the JSON data.
|
||||
"""
|
||||
required_fields = [
|
||||
"canonical_email",
|
||||
"email",
|
||||
"has_disability_access",
|
||||
"itemname",
|
||||
"locked",
|
||||
"notifications",
|
||||
"screenname",
|
||||
"verified",
|
||||
"lastlogin",
|
||||
"createdate",
|
||||
]
|
||||
for requried_field in required_fields:
|
||||
if requried_field not in json_data:
|
||||
raise ValueError(f"Missing required requried_field in JSON data: {requried_field}")
|
||||
|
||||
# Ensure session is of type ArchiveSession
|
||||
if session is None:
|
||||
session = get_session() # Default to ArchiveSession
|
||||
elif not isinstance(session, ArchiveSession):
|
||||
raise TypeError(f"Expected session to be of type ArchiveSession, got {type(session)}")
|
||||
|
||||
return cls(
|
||||
locked=json_data["locked"],
|
||||
verified=json_data["verified"],
|
||||
email=json_data["email"],
|
||||
canonical_email=json_data["canonical_email"],
|
||||
itemname=json_data["itemname"],
|
||||
screenname=json_data["screenname"],
|
||||
notifications=json_data["notifications"],
|
||||
has_disability_access=json_data["has_disability_access"],
|
||||
lastlogin=json_data["lastlogin"],
|
||||
createdate=json_data["createdate"],
|
||||
session=session
|
||||
)
|
||||
|
||||
def lock(self,
|
||||
comment: Optional[str] = None,
|
||||
session: Optional[ArchiveSession] = None) -> requests.Response:
|
||||
"""
|
||||
Lock the account.
|
||||
|
||||
Args:
|
||||
comment: An optional comment for the lock operation.
|
||||
session: Optional session to use for the request.
|
||||
|
||||
Returns:
|
||||
The response from the API.
|
||||
"""
|
||||
data = {'itemname': self.itemname, 'is_lock': '1'}
|
||||
if comment:
|
||||
data['comments'] = comment
|
||||
return self._post_api_request(
|
||||
self.API_BASE_URL,
|
||||
params=self.API_LOCK_UNLOCK_PARAMS,
|
||||
data=data,
|
||||
session=session
|
||||
)
|
||||
|
||||
def unlock(self,
|
||||
comment: Optional[str] = None,
|
||||
session: Optional[ArchiveSession] = None) -> requests.Response:
|
||||
"""
|
||||
Unlock the account.
|
||||
|
||||
Args:
|
||||
comment: An optional comment for the unlock operation.
|
||||
session: Optional session to use for the request.
|
||||
|
||||
Returns:
|
||||
The response from the API.
|
||||
"""
|
||||
data = {'itemname': self.itemname, 'is_lock': '0'}
|
||||
if comment:
|
||||
data['comments'] = comment
|
||||
return self._post_api_request(
|
||||
self.API_BASE_URL,
|
||||
params=self.API_LOCK_UNLOCK_PARAMS,
|
||||
data=data,
|
||||
session=session
|
||||
)
|
||||
|
||||
def to_dict(self) -> Dict:
|
||||
"""
|
||||
Converts the Account instance to a dictionary.
|
||||
|
||||
Returns:
|
||||
A dictionary representation of the Account instance.
|
||||
"""
|
||||
return {
|
||||
"locked": self.locked,
|
||||
"verified": self.verified,
|
||||
"email": self.email,
|
||||
"canonical_email": self.canonical_email,
|
||||
"itemname": self.itemname,
|
||||
"screenname": self.screenname,
|
||||
"notifications": self.notifications,
|
||||
"has_disability_access": self.has_disability_access,
|
||||
"lastlogin": self.lastlogin,
|
||||
"createdate": self.createdate,
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue