scratchattach 2.1.9__py3-none-any.whl → 2.1.10a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. scratchattach/__init__.py +28 -25
  2. scratchattach/cloud/__init__.py +2 -0
  3. scratchattach/cloud/_base.py +454 -282
  4. scratchattach/cloud/cloud.py +171 -168
  5. scratchattach/editor/__init__.py +21 -0
  6. scratchattach/editor/asset.py +199 -0
  7. scratchattach/editor/backpack_json.py +117 -0
  8. scratchattach/editor/base.py +142 -0
  9. scratchattach/editor/block.py +507 -0
  10. scratchattach/editor/blockshape.py +353 -0
  11. scratchattach/editor/build_defaulting.py +47 -0
  12. scratchattach/editor/comment.py +74 -0
  13. scratchattach/editor/commons.py +243 -0
  14. scratchattach/editor/extension.py +43 -0
  15. scratchattach/editor/field.py +90 -0
  16. scratchattach/editor/inputs.py +132 -0
  17. scratchattach/editor/meta.py +106 -0
  18. scratchattach/editor/monitor.py +175 -0
  19. scratchattach/editor/mutation.py +317 -0
  20. scratchattach/editor/pallete.py +91 -0
  21. scratchattach/editor/prim.py +170 -0
  22. scratchattach/editor/project.py +273 -0
  23. scratchattach/editor/sbuild.py +2837 -0
  24. scratchattach/editor/sprite.py +586 -0
  25. scratchattach/editor/twconfig.py +113 -0
  26. scratchattach/editor/vlb.py +134 -0
  27. scratchattach/eventhandlers/_base.py +99 -92
  28. scratchattach/eventhandlers/cloud_events.py +110 -103
  29. scratchattach/eventhandlers/cloud_recorder.py +26 -21
  30. scratchattach/eventhandlers/cloud_requests.py +460 -452
  31. scratchattach/eventhandlers/cloud_server.py +246 -244
  32. scratchattach/eventhandlers/cloud_storage.py +135 -134
  33. scratchattach/eventhandlers/combine.py +29 -27
  34. scratchattach/eventhandlers/filterbot.py +160 -159
  35. scratchattach/eventhandlers/message_events.py +41 -40
  36. scratchattach/other/other_apis.py +284 -212
  37. scratchattach/other/project_json_capabilities.py +475 -546
  38. scratchattach/site/_base.py +64 -46
  39. scratchattach/site/activity.py +414 -122
  40. scratchattach/site/backpack_asset.py +118 -84
  41. scratchattach/site/classroom.py +430 -142
  42. scratchattach/site/cloud_activity.py +107 -103
  43. scratchattach/site/comment.py +220 -190
  44. scratchattach/site/forum.py +400 -399
  45. scratchattach/site/project.py +806 -787
  46. scratchattach/site/session.py +1134 -867
  47. scratchattach/site/studio.py +611 -609
  48. scratchattach/site/user.py +835 -837
  49. scratchattach/utils/commons.py +243 -148
  50. scratchattach/utils/encoder.py +157 -156
  51. scratchattach/utils/enums.py +197 -190
  52. scratchattach/utils/exceptions.py +233 -206
  53. scratchattach/utils/requests.py +67 -59
  54. {scratchattach-2.1.9.dist-info → scratchattach-2.1.10a1.dist-info}/METADATA +155 -146
  55. scratchattach-2.1.10a1.dist-info/RECORD +62 -0
  56. {scratchattach-2.1.9.dist-info → scratchattach-2.1.10a1.dist-info}/WHEEL +1 -1
  57. {scratchattach-2.1.9.dist-info → scratchattach-2.1.10a1.dist-info/licenses}/LICENSE +21 -21
  58. scratchattach-2.1.9.dist-info/RECORD +0 -40
  59. {scratchattach-2.1.9.dist-info → scratchattach-2.1.10a1.dist-info}/top_level.txt +0 -0
@@ -1,103 +1,107 @@
1
- import time
2
- from ._base import BaseSiteComponent
3
-
4
- class CloudActivity(BaseSiteComponent):
5
- """
6
- Represents a cloud activity (a cloud variable set / creation / deletion).
7
-
8
- Attributes:
9
-
10
- :.username: The user who caused the cloud event (the user who added / set / deleted the cloud variable)
11
-
12
- :.var: The name of the cloud variable that was updated (specified without the cloud emoji)
13
-
14
- :.name: The name of the cloud variable that was updated (specified without the cloud emoji)
15
-
16
- :.type: The activity type
17
-
18
- :.timestamp: Then timestamp of when the action was performed
19
-
20
- :.value: If the cloud variable was set, then this attribute provides the value the cloud variable was set to
21
-
22
- :.cloud: The cloud (as object inheriting from scratchattach.Cloud.BaseCloud) that the cloud activity corresponds to
23
- """
24
-
25
- def __init__(self, **entries):
26
- # Set attributes every CloudActivity object needs to have:
27
- self._session = None
28
- self.cloud = None
29
- self.user = None
30
- self.username = None
31
- self.type = None
32
- self.timestamp = time.time()
33
-
34
- # Update attributes from entries dict:
35
- self.__dict__.update(entries)
36
-
37
- def update(self):
38
- print("Warning: CloudActivity objects can't be updated")
39
- return False # Objects of this type cannot be updated
40
-
41
- def __eq__(self, activity2):
42
- # CloudLogEvents needs to check if two activites are equal (to finde new ones), therefore CloudActivity objects need to be comparable
43
- return self.user == activity2.user and self.type == activity2.type and self.timestamp == activity2.timestamp and self.value == activity2.value and self.name == activity2.name
44
-
45
- def _update_from_dict(self, data) -> bool:
46
- try: self.name = data["name"]
47
- except Exception: pass
48
- try: self.var = data["name"]
49
- except Exception: pass
50
- try: self.value = data["value"]
51
- except Exception: pass
52
- try: self.user = data["user"]
53
- except Exception: pass
54
- try: self.username = data["user"]
55
- except Exception: pass
56
- try: self.timestamp = data["timestamp"]
57
- except Exception: pass
58
- try: self.type = data["verb"].replace("_var","")
59
- except Exception: pass
60
- try: self.type = data["method"]
61
- except Exception: pass
62
- try: self.cloud = data["cloud"]
63
- except Exception: pass
64
- return True
65
-
66
- def load_log_data(self):
67
- if self.cloud is None:
68
- print("Warning: There aren't cloud logs available for this cloud, therefore the user and exact timestamp can't be loaded")
69
- else:
70
- if hasattr(self.cloud, "logs"):
71
- logs = self.cloud.logs(filter_by_var_named=self.var, limit=100)
72
- matching = list(filter(lambda x: x.value == self.value and x.timestamp <= self.timestamp, logs))
73
- if matching == []:
74
- return False
75
- activity = matching[0]
76
- self.username = activity.username
77
- self.user = activity.username
78
- self.timestamp = activity.timestamp
79
- return True
80
- else:
81
- print("Warning: There aren't cloud logs available for this cloud, therefore the user and exact timestamp can't be loaded")
82
- return False
83
-
84
- def actor(self):
85
- """
86
- Returns the user that performed the cloud activity as scratchattach.user.User object
87
- """
88
- if self.username is None:
89
- return None
90
- from ..site import user
91
- from ..utils import exceptions
92
- return self._make_linked_object("username", self.username, user.User, exceptions.UserNotFound)
93
-
94
- def project(self):
95
- """
96
- Returns the project where the cloud activity was performed as scratchattach.project.Project object
97
- """
98
- if self.cloud is None:
99
- return None
100
- from ..site import project
101
- from ..utils import exceptions
102
- return self._make_linked_object("id", self.cloud.project_id, project.Project, exceptions.ProjectNotFound)
103
-
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from ._base import BaseSiteComponent
5
+
6
+
7
+
8
+ class CloudActivity(BaseSiteComponent):
9
+ """
10
+ Represents a cloud activity (a cloud variable set / creation / deletion).
11
+
12
+ Attributes:
13
+
14
+ :.username: The user who caused the cloud event (the user who added / set / deleted the cloud variable)
15
+
16
+ :.var: The name of the cloud variable that was updated (specified without the cloud emoji)
17
+
18
+ :.name: The name of the cloud variable that was updated (specified without the cloud emoji)
19
+
20
+ :.type: The activity type
21
+
22
+ :.timestamp: Then timestamp of when the action was performed
23
+
24
+ :.value: If the cloud variable was set, then this attribute provides the value the cloud variable was set to
25
+
26
+ :.cloud: The cloud (as object inheriting from scratchattach.Cloud.BaseCloud) that the cloud activity corresponds to
27
+ """
28
+
29
+ def __init__(self, **entries):
30
+ # Set attributes every CloudActivity object needs to have:
31
+ self._session = None
32
+ self.cloud = None
33
+ self.user = None
34
+ self.username = None
35
+ self.type = None
36
+ self.timestamp = time.time()
37
+
38
+ # Update attributes from entries dict:
39
+ self.__dict__.update(entries)
40
+
41
+ def update(self):
42
+ print("Warning: CloudActivity objects can't be updated")
43
+ return False # Objects of this type cannot be updated
44
+
45
+ def __eq__(self, activity2):
46
+ # CloudLogEvents needs to check if two activites are equal (to finde new ones), therefore CloudActivity objects need to be comparable
47
+ return self.user == activity2.user and self.type == activity2.type and self.timestamp == activity2.timestamp and self.value == activity2.value and self.name == activity2.name
48
+
49
+ def _update_from_dict(self, data) -> bool:
50
+ try: self.name = data["name"]
51
+ except Exception: pass
52
+ try: self.var = data["name"]
53
+ except Exception: pass
54
+ try: self.value = data["value"]
55
+ except Exception: pass
56
+ try: self.user = data["user"]
57
+ except Exception: pass
58
+ try: self.username = data["user"]
59
+ except Exception: pass
60
+ try: self.timestamp = data["timestamp"]
61
+ except Exception: pass
62
+ try: self.type = data["verb"].replace("_var","")
63
+ except Exception: pass
64
+ try: self.type = data["method"]
65
+ except Exception: pass
66
+ try: self.cloud = data["cloud"]
67
+ except Exception: pass
68
+ return True
69
+
70
+ def load_log_data(self):
71
+ if self.cloud is None:
72
+ print("Warning: There aren't cloud logs available for this cloud, therefore the user and exact timestamp can't be loaded")
73
+ else:
74
+ if hasattr(self.cloud, "logs"):
75
+ logs = self.cloud.logs(filter_by_var_named=self.var, limit=100)
76
+ matching = list(filter(lambda x: x.value == self.value and x.timestamp <= self.timestamp, logs))
77
+ if matching == []:
78
+ return False
79
+ activity = matching[0]
80
+ self.username = activity.username
81
+ self.user = activity.username
82
+ self.timestamp = activity.timestamp
83
+ return True
84
+ else:
85
+ print("Warning: There aren't cloud logs available for this cloud, therefore the user and exact timestamp can't be loaded")
86
+ return False
87
+
88
+ def actor(self):
89
+ """
90
+ Returns the user that performed the cloud activity as scratchattach.user.User object
91
+ """
92
+ if self.username is None:
93
+ return None
94
+ from ..site import user
95
+ from ..utils import exceptions
96
+ return self._make_linked_object("username", self.username, user.User, exceptions.UserNotFound)
97
+
98
+ def project(self):
99
+ """
100
+ Returns the project where the cloud activity was performed as scratchattach.project.Project object
101
+ """
102
+ if self.cloud is None:
103
+ return None
104
+ from ..site import project
105
+ from ..utils import exceptions
106
+ return self._make_linked_object("id", self.cloud.project_id, project.Project, exceptions.ProjectNotFound)
107
+
@@ -1,190 +1,220 @@
1
- """Comment class"""
2
-
3
- import json
4
- import re
5
-
6
- from ..utils import commons
7
-
8
- from . import user
9
- from . import session
10
- from . import project
11
- from . import studio
12
- from . import forum
13
- from ..utils import exceptions
14
- from ._base import BaseSiteComponent
15
- from ..utils.commons import headers
16
- from bs4 import BeautifulSoup
17
-
18
- from ..utils.requests import Requests as requests
19
-
20
- class Comment(BaseSiteComponent):
21
-
22
- '''
23
- Represents a Scratch comment (on a profile, studio or project)
24
- '''
25
-
26
- def str(self):
27
- return str(self.content)
28
-
29
- def __init__(self, **entries):
30
-
31
- # Set attributes every Comment object needs to have:
32
- self.id = None
33
- self._session = None
34
- self.source=None
35
- self.source_id = None
36
- self.cached_replies = None
37
- self.parent_id = None
38
- self.cached_parent_comment = None
39
- if not "source" in entries:
40
- "source" == "Unknown"
41
-
42
- # Update attributes from entries dict:
43
- self.__dict__.update(entries)
44
-
45
- def update(self):
46
- print("Warning: Comment objects can't be updated")
47
- return False # Objects of this type cannot be updated
48
-
49
- def _update_from_dict(self, data):
50
- try: self.id = data["id"]
51
- except Exception: pass
52
- try: self.parent_id = data["parent_id"]
53
- except Exception: pass
54
- try: self.commentee_id = data["commentee_id"]
55
- except Exception: pass
56
- try: self.content = data["content"]
57
- except Exception: pass
58
- try: self.datetime_created = data["datetime_created"]
59
- except Exception: pass
60
- try: self.author_name = data["author"]["username"]
61
- except Exception: pass
62
- try: self.author_id = data["author"]["id"]
63
- except Exception: pass
64
- try: self.written_by_scratchteam = data["author"]["scratchteam"]
65
- except Exception: pass
66
- try: self.reply_count = data["reply_count"]
67
- except Exception: pass
68
- try: self.source = data["source"]
69
- except Exception: pass
70
- try: self.source_id = data["source_id"]
71
- except Exception: pass
72
- return True
73
-
74
- # Methods for getting related entities
75
-
76
- def author(self):
77
- return self._make_linked_object("username", self.author_name, user.User, exceptions.UserNotFound)
78
-
79
- def place(self):
80
- """
81
- Returns the place (the project, profile or studio) where the comment was posted as Project, User, or Studio object.
82
-
83
- If the place can't be traced back, None is returned.
84
- """
85
- if self.source == "profile":
86
- return self._make_linked_object("username", self.source_id, user.User, exceptions.UserNotFound)
87
- if self.source == "studio":
88
- return self._make_linked_object("id", self.source_id, studio.Studio, exceptions.UserNotFound)
89
- if self.source == "project":
90
- return self._make_linked_object("id", self.source_id, project.Project, exceptions.UserNotFound)
91
-
92
- def parent_comment(self):
93
- if self.parent_id is None:
94
- return None
95
- if self.cached_parent_comment is not None:
96
- return self.cached_parent_comment
97
- if self.source == "profile":
98
- self.cached_parent_comment = user.User(username=self.source_id, _session=self._session).comment_by_id(self.parent_id)
99
- if self.source == "project":
100
- p = project.Project(id=self.source_id, _session=self._session)
101
- p.update()
102
- self.cached_parent_comment = p.comment_by_id(self.parent_id)
103
- if self.source == "studio":
104
- self.cached_parent_comment = studio.Studio(id=self.source_id, _session=self._session).comment_by_id(self.parent_id)
105
- return self.cached_parent_comment
106
-
107
- def replies(self, *, use_cache=True, limit=40, offset=0):
108
- """
109
- Keyword Arguments:
110
- use_cache (bool): Returns the replies cached on the first reply fetch. This makes it SIGNIFICANTLY faster for profile comments. Warning: For profile comments, the replies are retrieved and cached on object creation.
111
- """
112
- if (self.cached_replies is None) or (use_cache is False):
113
- if self.source == "profile":
114
- self.cached_replies = user.User(username=self.source_id, _session=self._session).comment_by_id(self.id).cached_replies[offset:offset+limit]
115
- if self.source == "project":
116
- p = project.Project(id=self.source_id, _session=self._session)
117
- p.update()
118
- self.cached_replies = p.comment_replies(comment_id=self.id, limit=limit, offset=offset)
119
- if self.source == "studio":
120
- self.cached_replies = studio.Studio(id=self.source_id, _session=self._session).comment_replies(comment_id=self.id, limit=limit, offset=offset)
121
- return self.cached_replies
122
-
123
- # Methods for dealing with the comment
124
-
125
- def reply(self, content, *, commentee_id=None):
126
- """
127
- Posts a reply comment to the comment.
128
-
129
- Warning:
130
- Scratch only shows comments replying to top-level comments, and all replies to replies are actually replies to top-level comments in the API.
131
-
132
- Therefore, if this comment is a reply, this method will not reply to the comment itself but to the corresponding top-level comment.
133
-
134
- Args:
135
- content (str): Comment content to post.
136
-
137
- Keyword args:
138
- commentee_id (None or str): If set to None (default), it will automatically fill out the commentee ID with the user ID of the parent comment author. Set it to "" to mention no user.
139
-
140
-
141
- Returns:
142
- scratchattach.Comment: The created comment.
143
- """
144
-
145
- self._assert_auth()
146
- parent_id = str(self.id)
147
- if self.parent_id is not None:
148
- parent_id = str(self.parent_id)
149
- if commentee_id is None:
150
- if "author_id" in self.__dict__:
151
- commentee_id = self.author_id
152
- else:
153
- commentee_id = ""
154
- if self.source == "profile":
155
- return user.User(username=self.source_id, _session=self._session).reply_comment(content, parent_id=str(parent_id), commentee_id=commentee_id)
156
- if self.source == "project":
157
- p = project.Project(id=self.source_id, _session=self._session)
158
- p.update()
159
- return p.reply_comment(content, parent_id=str(parent_id), commentee_id=commentee_id)
160
- if self.source == "studio":
161
- return studio.Studio(id=self.source_id, _session=self._session).reply_comment(content, parent_id=str(parent_id), commentee_id=commentee_id)
162
-
163
-
164
- def delete(self):
165
- """
166
- Deletes the comment.
167
- """
168
- self._assert_auth()
169
- if self.source == "profile":
170
- user.User(username=self.source_id, _session=self._session).delete_comment(comment_id=self.id)
171
- if self.source == "project":
172
- p = project.Project(id=self.source_id, _session=self._session)
173
- p.update()
174
- p.delete_comment(comment_id=self.id)
175
- if self.source == "studio":
176
- studio.Studio(id=self.source_id, _session=self._session).delete_comment(comment_id=self.id)
177
-
178
- def report(self):
179
- """
180
- Reports the comment to the Scratch team.
181
- """
182
- self._assert_auth()
183
- if self.source == "profile":
184
- user.User(username=self.source_id, _session=self._session).report_comment(comment_id=self.id)
185
- if self.source == "project":
186
- p = project.Project(id=self.source_id, _session=self._session)
187
- p.update()
188
- p.report_comment(comment_id=self.id)
189
- if self.source == "studio":
190
- studio.Studio(id=self.source_id, _session=self._session).report_comment(comment_id=self.id)
1
+ """Comment class"""
2
+ from __future__ import annotations
3
+
4
+ from . import user, project, studio
5
+ from ._base import BaseSiteComponent
6
+ from ..utils import exceptions
7
+
8
+
9
+ class Comment(BaseSiteComponent):
10
+ """
11
+ Represents a Scratch comment (on a profile, studio or project)
12
+ """
13
+
14
+ def str(self):
15
+ return str(self.content)
16
+
17
+ def __init__(self, **entries):
18
+
19
+ # Set attributes every Comment object needs to have:
20
+ self.id = None
21
+ self._session = None
22
+ self.source = None
23
+ self.source_id = None
24
+ self.cached_replies = None
25
+ self.parent_id = None
26
+ self.cached_parent_comment = None
27
+
28
+ # Update attributes from entries dict:
29
+ self.__dict__.update(entries)
30
+
31
+ if "source" not in entries:
32
+ self.source = "Unknown"
33
+
34
+ def update(self):
35
+ print("Warning: Comment objects can't be updated")
36
+ return False # Objects of this type cannot be updated
37
+
38
+ def _update_from_dict(self, data):
39
+ try:
40
+ self.id = data["id"]
41
+ except Exception:
42
+ pass
43
+ try:
44
+ self.parent_id = data["parent_id"]
45
+ except Exception:
46
+ pass
47
+ try:
48
+ self.commentee_id = data["commentee_id"]
49
+ except Exception:
50
+ pass
51
+ try:
52
+ self.content = data["content"]
53
+ except Exception:
54
+ pass
55
+ try:
56
+ self.datetime_created = data["datetime_created"]
57
+ except Exception:
58
+ pass
59
+ try:
60
+ self.author_name = data["author"]["username"]
61
+ except Exception:
62
+ pass
63
+ try:
64
+ self.author_id = data["author"]["id"]
65
+ except Exception:
66
+ pass
67
+ try:
68
+ self.written_by_scratchteam = data["author"]["scratchteam"]
69
+ except Exception:
70
+ pass
71
+ try:
72
+ self.reply_count = data["reply_count"]
73
+ except Exception:
74
+ pass
75
+ try:
76
+ self.source = data["source"]
77
+ except Exception:
78
+ pass
79
+ try:
80
+ self.source_id = data["source_id"]
81
+ except Exception:
82
+ pass
83
+ return True
84
+
85
+ # Methods for getting related entities
86
+
87
+ def author(self) -> user.User:
88
+ return self._make_linked_object("username", self.author_name, user.User, exceptions.UserNotFound)
89
+
90
+ def place(self) -> user.User | studio.Studio | project.Project:
91
+ """
92
+ Returns the place (the project, profile or studio) where the comment was posted as Project, User, or Studio object.
93
+
94
+ If the place can't be traced back, None is returned.
95
+ """
96
+ if self.source == "profile":
97
+ return self._make_linked_object("username", self.source_id, user.User, exceptions.UserNotFound)
98
+ if self.source == "studio":
99
+ return self._make_linked_object("id", self.source_id, studio.Studio, exceptions.UserNotFound)
100
+ if self.source == "project":
101
+ return self._make_linked_object("id", self.source_id, project.Project, exceptions.UserNotFound)
102
+
103
+ def parent_comment(self) -> Comment | None:
104
+ if self.parent_id is None:
105
+ return None
106
+
107
+ if self.cached_parent_comment is not None:
108
+ return self.cached_parent_comment
109
+
110
+ if self.source == "profile":
111
+ self.cached_parent_comment = user.User(username=self.source_id, _session=self._session).comment_by_id(
112
+ self.parent_id)
113
+
114
+ elif self.source == "project":
115
+ p = project.Project(id=self.source_id, _session=self._session)
116
+ p.update()
117
+ self.cached_parent_comment = p.comment_by_id(self.parent_id)
118
+
119
+ elif self.source == "studio":
120
+ self.cached_parent_comment = studio.Studio(id=self.source_id, _session=self._session).comment_by_id(
121
+ self.parent_id)
122
+
123
+ return self.cached_parent_comment
124
+
125
+ def replies(self, *, use_cache: bool = True, limit=40, offset=0):
126
+ """
127
+ Keyword Arguments:
128
+ use_cache (bool): Returns the replies cached on the first reply fetch. This makes it SIGNIFICANTLY faster for profile comments. Warning: For profile comments, the replies are retrieved and cached on object creation.
129
+ """
130
+ if (self.cached_replies is None) or (not use_cache):
131
+ if self.source == "profile":
132
+ self.cached_replies = user.User(username=self.source_id, _session=self._session).comment_by_id(
133
+ self.id).cached_replies[offset:offset + limit]
134
+
135
+ elif self.source == "project":
136
+ p = project.Project(id=self.source_id, _session=self._session)
137
+ p.update()
138
+ self.cached_replies = p.comment_replies(comment_id=self.id, limit=limit, offset=offset)
139
+
140
+ elif self.source == "studio":
141
+ self.cached_replies = studio.Studio(id=self.source_id, _session=self._session).comment_replies(
142
+ comment_id=self.id, limit=limit, offset=offset)
143
+
144
+ return self.cached_replies
145
+
146
+ # Methods for dealing with the comment
147
+
148
+ def reply(self, content, *, commentee_id=None):
149
+ """
150
+ Posts a reply comment to the comment.
151
+
152
+ Warning:
153
+ Scratch only shows comments replying to top-level comments, and all replies to replies are actually replies to top-level comments in the API.
154
+
155
+ Therefore, if this comment is a reply, this method will not reply to the comment itself but to the corresponding top-level comment.
156
+
157
+ Args:
158
+ content (str): Comment content to post.
159
+
160
+ Keyword args:
161
+ commentee_id (None or str): If set to None (default), it will automatically fill out the commentee ID with the user ID of the parent comment author. Set it to "" to mention no user.
162
+
163
+
164
+ Returns:
165
+ scratchattach.Comment: The created comment.
166
+ """
167
+
168
+ self._assert_auth()
169
+ parent_id = str(self.id)
170
+ if self.parent_id is not None:
171
+ parent_id = str(self.parent_id)
172
+ if commentee_id is None:
173
+ if "author_id" in self.__dict__:
174
+ commentee_id = self.author_id
175
+ else:
176
+ commentee_id = ""
177
+ if self.source == "profile":
178
+ return user.User(username=self.source_id, _session=self._session).reply_comment(content,
179
+ parent_id=str(parent_id),
180
+ commentee_id=commentee_id)
181
+ if self.source == "project":
182
+ p = project.Project(id=self.source_id, _session=self._session)
183
+ p.update()
184
+ return p.reply_comment(content, parent_id=str(parent_id), commentee_id=commentee_id)
185
+ if self.source == "studio":
186
+ return studio.Studio(id=self.source_id, _session=self._session).reply_comment(content,
187
+ parent_id=str(parent_id),
188
+ commentee_id=commentee_id)
189
+
190
+ def delete(self):
191
+ """
192
+ Deletes the comment.
193
+ """
194
+ self._assert_auth()
195
+ if self.source == "profile":
196
+ user.User(username=self.source_id, _session=self._session).delete_comment(comment_id=self.id)
197
+
198
+ elif self.source == "project":
199
+ p = project.Project(id=self.source_id, _session=self._session)
200
+ p.update()
201
+ p.delete_comment(comment_id=self.id)
202
+
203
+ elif self.source == "studio":
204
+ studio.Studio(id=self.source_id, _session=self._session).delete_comment(comment_id=self.id)
205
+
206
+ def report(self):
207
+ """
208
+ Reports the comment to the Scratch team.
209
+ """
210
+ self._assert_auth()
211
+ if self.source == "profile":
212
+ user.User(username=self.source_id, _session=self._session).report_comment(comment_id=self.id)
213
+
214
+ elif self.source == "project":
215
+ p = project.Project(id=self.source_id, _session=self._session)
216
+ p.update()
217
+ p.report_comment(comment_id=self.id)
218
+
219
+ elif self.source == "studio":
220
+ studio.Studio(id=self.source_id, _session=self._session).report_comment(comment_id=self.id)