Skip to content

Commit 35828df

Browse files
committed
feat: Adds new classes and methods
feat: Adds class LemmyLocalUser feat: Adds class LemmyRegistrationApplication feat: adds method get_registration_applications
1 parent 7353851 commit 35828df

File tree

9 files changed

+239
-44
lines changed

9 files changed

+239
-44
lines changed

examples/regapps_class.py

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
## python examples/regapps_class
2+
3+
import argparse
4+
import os
5+
from pythorhead import Lemmy
6+
7+
arg_parser = argparse.ArgumentParser()
8+
arg_parser.add_argument(
9+
"-d",
10+
"--lemmy_domain",
11+
action="store",
12+
required=False,
13+
type=str,
14+
help="the domain in which to look for this user",
15+
)
16+
arg_parser.add_argument(
17+
"-u",
18+
"--lemmy_username",
19+
action="store",
20+
required=False,
21+
type=str,
22+
help="Which user to authenticate as",
23+
)
24+
arg_parser.add_argument(
25+
"-p",
26+
"--lemmy_password",
27+
action="store",
28+
required=False,
29+
type=str,
30+
help="Which password to authenticate with",
31+
)
32+
args = arg_parser.parse_args()
33+
34+
35+
lemmy_domain = args.lemmy_domain
36+
if not lemmy_domain:
37+
lemmy_domain = os.getenv("LEMMY_DOMAIN", "lemmy.dbzer0.com")
38+
if not lemmy_domain:
39+
raise Exception("You need to provide a lemmy domain via env var or arg")
40+
41+
lemmy_username = args.lemmy_username
42+
if not lemmy_username:
43+
lemmy_username = os.getenv("LEMMY_USERNAME")
44+
45+
lemmy_password = args.lemmy_password
46+
if not lemmy_password:
47+
lemmy_password = os.getenv("LEMMY_PASSWORD")
48+
49+
lemmy = Lemmy(f"https://{lemmy_domain}", raise_exceptions=True, request_timeout=2)
50+
if lemmy_username and lemmy_password:
51+
login = lemmy.log_in(lemmy_username, lemmy_password)
52+
regapps = lemmy.get_registration_applications(limit=10)
53+
if not regapps:
54+
print("No registration applications found")
55+
for regapp in regapps:
56+
print(f"Application from user '{regapp.creator.name}' {regapp.get_application_status()}")

examples/user_class.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
## python examples/user.py db0
22

33
import argparse
4-
import json
54
import os
65
from pythorhead import Lemmy
76

@@ -51,7 +50,7 @@
5150
lemmy = Lemmy(f"https://{lemmy_domain}", raise_exceptions=True, request_timeout=2)
5251
if lemmy_username and lemmy_password:
5352
login = lemmy.log_in(lemmy_username, lemmy_password)
54-
user = lemmy.user.get(username=args.username, return_user_object = True)
53+
user = lemmy.get_user(username=args.username)
5554
if user:
5655
print(user.asjson(indent=4))
5756
else:

pythorhead/class_methods.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from pythorhead.classes.admin import LemmyRegistrationApplication, LemmyLocalUser
2+
from pythorhead.classes.user import LemmyUser
3+
4+
def get_user(lemmy, **kwargs) -> LemmyUser | None:
5+
return_json = lemmy.user.get(**kwargs)
6+
if return_json is None:
7+
return
8+
data_dict = return_json['person_view']['person']
9+
data_dict['is_admin'] = return_json['person_view']['is_admin']
10+
data_dict['comments'] = return_json['comments']
11+
data_dict['posts'] = return_json['posts']
12+
return LemmyUser.from_dict(data_dict, lemmy)
13+
14+
def get_applications(lemmy, **kwargs) -> list[LemmyRegistrationApplication]:
15+
return_json = lemmy.admin.list_applications(**kwargs)
16+
regapps = []
17+
if return_json is None:
18+
return regapps
19+
for data in return_json["registration_applications"]:
20+
data_dict = data["registration_application"]
21+
data_dict["creator_local_user"] = LemmyLocalUser.from_dict(data["creator_local_user"], lemmy)
22+
data_dict["creator"] = LemmyUser.from_dict(data["creator"], lemmy)
23+
data_dict["admin"] = None
24+
if data.get("admin"):
25+
admin_dict = data["admin"]
26+
admin_dict["is_admin"] = True
27+
data_dict["admin"] = LemmyUser.from_dict(admin_dict, lemmy)
28+
regapps.append(LemmyRegistrationApplication.from_dict(data_dict, lemmy))
29+
return regapps

pythorhead/classes/admin.py

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from datetime import datetime
2+
from dateutil import parser
3+
from pythorhead.classes.base import LemmyBaseClass
4+
from pythorhead.classes.user import LemmyUser
5+
from dataclasses import dataclass
6+
from pythorhead.types import SortType, ListingType, LanguageType
7+
from enum import Enum
8+
9+
# TODO: Convert to StrEnum in python 3.11
10+
class ApplicationStatus(str, Enum):
11+
Pending = "pending"
12+
Accepted = "accepted"
13+
Denied = "denied"
14+
15+
16+
@dataclass
17+
class LemmyLocalUser(LemmyBaseClass):
18+
id: int
19+
person_id: int
20+
email: str
21+
show_nsfw: bool
22+
theme: str
23+
default_sort_type: SortType
24+
default_listing_type: ListingType
25+
interface_language: LanguageType
26+
show_avatars: bool
27+
send_notifications_to_email: bool
28+
show_scores: bool
29+
show_bot_accounts: bool
30+
show_read_posts: bool
31+
email_verified: bool
32+
accepted_application: bool
33+
open_links_in_new_tab: bool
34+
blur_nsfw: bool
35+
auto_expand: bool
36+
infinite_scroll_enabled: bool
37+
admin: bool
38+
post_listing_mode: str
39+
totp_2fa_enabled: bool
40+
enable_keyboard_navigation: bool
41+
enable_animated_images: bool
42+
collapse_bot_comments: bool
43+
published: datetime | None = None
44+
45+
@classmethod
46+
def from_dict(cls, data_dict: dict, lemmy) -> 'LemmyRegistrationApplication':
47+
# Convert string to datetime for ban_expires if it exists
48+
for key in {'published'}:
49+
if key in data_dict and data_dict[key]:
50+
data_dict[key] = parser.isoparse(data_dict[key])
51+
for key in {'default_sort_type','default_listing_type'}:
52+
if key in data_dict and data_dict[key]:
53+
data_dict[key] = cls.__annotations__[key](data_dict[key])
54+
for key in {'interface_language'}:
55+
if key in data_dict and data_dict[key]:
56+
data_dict[key] = cls.__annotations__[key][data_dict[key].upper()]
57+
new_class = cls(**data_dict)
58+
new_class._lemmy = lemmy
59+
new_class._origin = data_dict
60+
return new_class
61+
62+
63+
64+
@dataclass
65+
class LemmyRegistrationApplication(LemmyBaseClass):
66+
id: int
67+
local_user_id: int
68+
answer: str
69+
published: datetime
70+
creator_local_user: dict
71+
creator: LemmyUser
72+
creator_local_user: LemmyLocalUser
73+
creator: LemmyUser
74+
admin_id: int | None = None
75+
deny_reason: str | None = None
76+
admin: LemmyUser | None = None
77+
78+
79+
@classmethod
80+
def from_dict(cls, data_dict: dict, lemmy) -> 'LemmyRegistrationApplication':
81+
# Convert string to datetime for ban_expires if it exists
82+
for key in {'published'}:
83+
if key in data_dict and data_dict[key]:
84+
data_dict[key] = parser.isoparse(data_dict[key])
85+
new_class = cls(**data_dict)
86+
new_class._lemmy = lemmy
87+
new_class._origin = data_dict
88+
return new_class
89+
90+
def get_application_status(self) -> str:
91+
if self.creator_local_user.accepted_application:
92+
return ApplicationStatus.Accepted
93+
elif self.deny_reason:
94+
return ApplicationStatus.Denied
95+
return ApplicationStatus.Pending

pythorhead/classes/base.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from dataclasses import dataclass, asdict, field
2+
from pythorhead.utils import json_serializer
3+
4+
import json
5+
6+
7+
@dataclass
8+
class LemmyBaseClass:
9+
# The owning lemmy instance. We use it to reach the API classes
10+
_lemmy: 'Lemmy' = field(init=None)
11+
# The original data dict from which we created this class
12+
_origin: dict = field(init=None)
13+
14+
def asdict(self):
15+
selfdict = asdict(self)
16+
del selfdict['_lemmy']
17+
del selfdict['_origin']
18+
return selfdict
19+
20+
def asjson(self, indent=4):
21+
return json.dumps(self.asdict(), indent=indent, default=json_serializer)
22+

pythorhead/classes/user.py

+21-29
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
from dataclasses import dataclass, asdict
21
from datetime import datetime
32
from dateutil import parser
4-
from pythorhead.utils import json_serializer
5-
6-
import json
3+
from pythorhead.classes.base import LemmyBaseClass
4+
from dataclasses import dataclass
75

86
@dataclass
9-
class LemmyUser:
7+
class LemmyUser(LemmyBaseClass):
108
id: int
119
name: str
1210
banned: bool
@@ -16,28 +14,29 @@ class LemmyUser:
1614
deleted: bool
1715
bot_account: bool
1816
instance_id: int
19-
is_admin: bool
17+
is_admin: bool = False
2018
display_name: str | None = None
2119
bio: str | None = None
2220
avatar: str | None = None
2321
banner: str | None = None
2422
matrix_user_id: str | None = None
2523
ban_expires: datetime | None = None
2624
updated: datetime | None = None
25+
#TODO Convert to classes
2726
comments: list[dict] = None
2827
posts: list[dict] = None
29-
# The owning lemmy instance. We use it to reach the API classes
30-
lemmy = None
3128

3229
@classmethod
33-
def from_dict(cls, person_dict: dict, lemmy) -> 'LemmyUser':
30+
def from_dict(cls, data_dict: dict, lemmy) -> 'LemmyUser':
3431
# Convert string to datetime for ban_expires if it exists
32+
3533
for key in {'ban_expires', 'updates', 'published'}:
36-
if key in person_dict and person_dict[key]:
37-
person_dict[key] = parser.isoparse(person_dict[key])
38-
new_user = cls(**person_dict)
39-
new_user.lemmy = lemmy
40-
return new_user
34+
if key in data_dict and data_dict[key]:
35+
data_dict[key] = parser.isoparse(data_dict[key])
36+
new_class = cls(**data_dict)
37+
new_class._lemmy = lemmy
38+
new_class._origin = data_dict
39+
return new_class
4140

4241
def refresh(self) -> None:
4342
"""
@@ -46,7 +45,7 @@ def refresh(self) -> None:
4645
Args:
4746
new_data: Dictionary containing updated user data
4847
"""
49-
fresh_data = self.lemmy.user.get(person_id=self.id)
48+
fresh_data = self._lemmy.user.get(person_id=self.id)
5049
user_dict = fresh_data['person_view']['person']
5150
user_dict['is_admin'] = fresh_data['person_view']['is_admin']
5251
user_dict['comments'] = fresh_data['comments']
@@ -60,15 +59,15 @@ def refresh(self) -> None:
6059

6160

6261
def purge(self) -> None:
63-
self.lemmy.user.purge(person_id=self.person_id)
62+
self._lemmy.user.purge(person_id=self.person_id)
6463

6564
def ban(self,
6665
ban: bool = True,
6766
expires: datetime | int | None = None,
6867
reason: str | None = None,
6968
remove_data: bool | None = None
7069
) -> None:
71-
self.lemmy.user.ban(
70+
self._lemmy.user.ban(
7271
person_id=self.person_id,
7372
ban = ban,
7473
expires = expires,
@@ -78,9 +77,9 @@ def ban(self,
7877
self.refresh()
7978

8079
def update(self):
81-
if self.lemmy.user._requestor.logged_in_username != self.name:
80+
if self._lemmy.user._requestor.logged_in_username != self.name:
8281
raise Exception("Cannot update user details for anyone but the currently logged-in user.")
83-
self.lemmy.user.save_user_settings(
82+
self._lemmy.user.save_user_settings(
8483
avatar=self.avatar,
8584
banner=self.banner,
8685
display_name=self.display_name,
@@ -91,20 +90,13 @@ def update(self):
9190
self.refresh()
9291

9392
def set_settings(self, **kwargs):
94-
if self.lemmy.user._requestor.logged_in_username != self.name:
93+
if self._lemmy.user._requestor.logged_in_username != self.name:
9594
raise Exception("Cannot update user settings for anyone but the currently logged-in user.")
96-
self.lemmy.user.save_user_settings(**kwargs)
95+
self._lemmy.user.save_user_settings(**kwargs)
9796
self.refresh()
98-
99-
def asdict(self):
100-
return asdict(self)
101-
102-
def asjson(self, indent=4):
103-
selfdict = self.asdict()
104-
return json.dumps(selfdict, indent=indent, default=json_serializer)
10597

10698
def pm(self, content):
107-
self.lemmy.private_message(
99+
self._lemmy.private_message(
108100
content=content,
109101
recipient_id=self.id,
110102
)

pythorhead/comment.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from pythorhead.requestor import Request, Requestor
44
from pythorhead.types import CommentSortType, LanguageType, ListingType
5-
5+
import logging
66

77
class Comment:
88
def __init__(self, _requestor: Requestor):
@@ -47,6 +47,8 @@ def list( # noqa: A003
4747
list_comment["community_name"] = community_name
4848
if limit is not None:
4949
list_comment["limit"] = limit
50+
if max_depth is not None:
51+
logging.warning("list comments 'limit' param is ignored when 'max_depth' is set")
5052
if max_depth is not None:
5153
list_comment["max_depth"] = max_depth
5254
if page is not None:
@@ -61,7 +63,6 @@ def list( # noqa: A003
6163
list_comment["sort"] = sort.value
6264
if type_ is not None:
6365
list_comment["type_"] = type_.value
64-
6566
if data := self._requestor.api(Request.GET, "/comment/list", params=list_comment):
6667
return data["comments"]
6768
return []

0 commit comments

Comments
 (0)