1
1
"""
2
- discourse.py Functions for to send and retrieve posts to/fraom the discourse platform.
2
+ discourse.py Functions for to send and retrieve posts to/from the discourse platform.
3
+ Discourse is not considered available if the DISCOURSE_API_KEY is not set.
3
4
"""
4
5
import logging
5
6
import os
6
7
from typing import Tuple
7
8
9
+ import pydiscourse
8
10
from django .conf import settings
9
- from pydiscourse import DiscourseClient
10
11
11
12
from viewer .models import DiscourseCategory , DiscourseTopic
12
13
13
14
logger = logging .getLogger (__name__ )
14
15
15
16
17
+ def _get_client ():
18
+ """Create Discourse client for the configured fragalysis user"""
19
+ assert settings .DISCOURSE_API_KEY
20
+ return pydiscourse .DiscourseClient (
21
+ settings .DISCOURSE_HOST ,
22
+ api_username = settings .DISCOURSE_USER ,
23
+ api_key = settings .DISCOURSE_API_KEY ,
24
+ )
25
+
26
+
27
+ def _get_user_client (user ):
28
+ """Create Discourse client for user.
29
+ The code would normally have checked that the user exists before calling this.
30
+ """
31
+ assert settings .DISCOURSE_API_KEY
32
+ return pydiscourse .DiscourseClient (
33
+ settings .DISCOURSE_HOST ,
34
+ api_username = user .username ,
35
+ api_key = settings .DISCOURSE_API_KEY ,
36
+ )
37
+
38
+
16
39
def get_user (client , username ) -> Tuple [bool , str , int ]:
17
40
"""Call discourse API users to retrieve user by username."""
18
41
logger .info ('+ discourse.get_user' )
@@ -67,26 +90,24 @@ def create_category(
67
90
68
91
69
92
def process_category (category_details ):
70
- """Check category is present in Table - If not create it in Discourse and store the id returned.."""
93
+ """Check category is present in Table.
94
+ If not create it in Discourse and store the id returned.
95
+ """
71
96
72
- # DISCOURSE_DEV_POST_SUFFIX is used to differentiate the same target name from different dev systems in Discourse
97
+ # DISCOURSE_DEV_POST_SUFFIX is used to differentiate the same target name
98
+ # from different dev systems in Discourse.
73
99
# It is not intended to be used for production when there is a dedicated Discourse.
74
100
category_name = (
75
101
category_details ['category_name' ] + settings .DISCOURSE_DEV_POST_SUFFIX
76
102
)
77
103
78
- # Create Discourse client for fragalysis user
79
- client = DiscourseClient (
80
- settings .DISCOURSE_HOST ,
81
- api_username = settings .DISCOURSE_USER ,
82
- api_key = settings .DISCOURSE_API_KEY ,
83
- )
84
-
85
104
try :
86
105
category = DiscourseCategory .objects .get (category_name = category_name )
87
106
category_id = category .discourse_category_id
88
107
post_url = os .path .join (settings .DISCOURSE_HOST , 'c' , str (category_id ))
89
108
except DiscourseCategory .DoesNotExist :
109
+ # Create Discourse client for fragalysis user
110
+ client = _get_client ()
90
111
category_id , post_url = create_category (
91
112
client ,
92
113
category_name ,
@@ -107,49 +128,54 @@ def create_post(user, post_details, category_id=None, topic_id=None):
107
128
if not user .is_authenticated :
108
129
return True , 'Please logon to Post to Discourse' , 0 , ''
109
130
110
- # Create Discourse client for user
111
- client = DiscourseClient (
112
- settings .DISCOURSE_HOST ,
113
- api_username = user .username ,
114
- api_key = settings .DISCOURSE_API_KEY ,
115
- )
116
-
117
131
# Check user is present in Discourse
132
+ client = _get_client ()
118
133
error , error_message , user_id = get_user (client , user .username )
119
134
if user_id == 0 :
120
135
return error , error_message , 0 , ''
121
136
122
137
title = post_details ['title' ]
123
138
content = post_details ['content' ]
124
- tags = post_details ['tags' ]
125
-
126
- if tags is None :
127
- tags = []
139
+ tags = post_details ['tags' ] if 'tags' in post_details else []
128
140
129
141
if len (content ) < 20 :
130
142
return True , 'Content must be more than 20 characters long in Discourse' , 0 , ''
131
143
132
- post = client .create_post (content , category_id , topic_id , title , tags )
133
- # posts url = / t / {topic_id} / {post_number}
144
+ # Try to create a discourse topic post (a topic).
145
+ # This might fail, especially if the topic title already exists.
146
+ client = _get_user_client (user )
147
+ try :
148
+ post = client .create_post (content , category_id , topic_id , title , tags )
149
+ except pydiscourse .exceptions .DiscourseClientError as dex :
150
+ return True , dex .message , 0 , ''
151
+
152
+ # A topic's url is {URL}/t/{topic_id}/{post_number}
134
153
post_url = os .path .join (
135
154
settings .DISCOURSE_HOST , 't' , str (post ['topic_id' ]), str (post ['post_number' ])
136
155
)
137
- logger .info ('- discourse.create_post' )
138
156
157
+ logger .info ('- discourse.create_post' )
139
158
return error , error_message , post ['topic_id' ], post_url
140
159
141
160
142
161
def process_post (category_id , post_details , user ):
143
- """Check topic is present in Discourse. IF exists then post, otherwise create new topic for category"""
162
+ """Check topic is present in Discourse.
163
+ If it exists then post, otherwise create new topic for category
164
+ """
165
+ assert category_id
166
+ assert 'title' in post_details
167
+
144
168
error = False
145
169
error_message = ''
146
170
147
- # DISCOURSE_DEV_POST_SUFFIX is used to differentiate the same target name from different dev systems in Discourse
171
+ # DISCOURSE_DEV_POST_SUFFIX is used to differentiate the same target name
172
+ # from different dev systems in Discourse.
148
173
# It is not intended to be used for production when there is a dedicated Discourse.
149
174
post_details ['title' ] = post_details ['title' ] + settings .DISCOURSE_DEV_POST_SUFFIX
150
175
151
- try :
152
- topic = DiscourseTopic .objects .get (topic_title = post_details ['title' ])
176
+ if topic := DiscourseTopic .objects .filter (
177
+ topic_title = post_details ['title' ]
178
+ ).first ():
153
179
topic_id = topic .discourse_topic_id
154
180
if post_details ['content' ] == '' :
155
181
# No content - Return the URL for the topic
@@ -159,7 +185,7 @@ def process_post(category_id, post_details, user):
159
185
error , error_message , _ , post_url = create_post (
160
186
user , post_details , topic_id = topic_id
161
187
)
162
- except DiscourseTopic . DoesNotExist :
188
+ else :
163
189
# Create Topic for Category
164
190
error , error_message , topic_id , post_url = create_post (
165
191
user , post_details , category_id = category_id
@@ -170,6 +196,7 @@ def process_post(category_id, post_details, user):
170
196
author = user ,
171
197
discourse_topic_id = topic_id ,
172
198
)
199
+
173
200
return error , error_message , topic_id , post_url
174
201
175
202
@@ -178,8 +205,8 @@ def topic_posts(client, topic_id):
178
205
logger .info ('+ discourse.topic_posts' )
179
206
180
207
posts = client .topic_posts (topic_id )
181
- logger . info ( posts )
182
- logger .info ('- discourse.topic_posts' )
208
+
209
+ logger .info ('- discourse.topic_posts posts=%s' , posts )
183
210
return posts
184
211
185
212
@@ -195,8 +222,10 @@ def create_discourse_post(user, category_details=None, post_details=None):
195
222
created_date=<date>, tags[list]}
196
223
:return: error or url of post.
197
224
"""
225
+ assert user
198
226
199
227
logger .info ('+ discourse.create_discourse_post' )
228
+
200
229
error = False
201
230
error_message = ''
202
231
@@ -223,7 +252,7 @@ def create_discourse_post(user, category_details=None, post_details=None):
223
252
224
253
225
254
def list_discourse_posts_for_topic (topic_title ):
226
- """Call discourse APIs to retreive posts for the given topic
255
+ """Call discourse APIs to retrieve posts for the given topic
227
256
228
257
Makes the translation from Fragalysis topic_name to discourse id.
229
258
@@ -234,24 +263,15 @@ def list_discourse_posts_for_topic(topic_title):
234
263
posts = ''
235
264
error = False
236
265
237
- # DISCOURSE_DEV_POST_SUFFIX is used to differentiate the same target name from different dev systems in Discourse
266
+ # DISCOURSE_DEV_POST_SUFFIX is used to differentiate the same target name
267
+ # from different dev systems in Discourse.
238
268
# It is not intended to be used for production when there is a dedicated Discourse.
239
269
if topic_title :
240
270
topic_title = topic_title + settings .DISCOURSE_DEV_POST_SUFFIX
241
271
242
- # Get topic_id for title
243
- try :
244
- topic = DiscourseTopic .objects .get (topic_title = topic_title )
245
- except DiscourseTopic .DoesNotExist :
246
- topic = None
247
-
248
- if topic :
272
+ if topic := DiscourseTopic .objects .filter (topic_title = topic_title ).first ():
249
273
# Create Discourse client
250
- client = DiscourseClient (
251
- settings .DISCOURSE_HOST ,
252
- api_username = settings .DISCOURSE_USER ,
253
- api_key = settings .DISCOURSE_API_KEY ,
254
- )
274
+ client = _get_client ()
255
275
posts = topic_posts (client , topic .discourse_topic_id )
256
276
else :
257
277
error = True
@@ -261,18 +281,10 @@ def list_discourse_posts_for_topic(topic_title):
261
281
262
282
263
283
def check_discourse_user (user ):
264
- """Call discourse API to check discourse user exists"""
265
-
266
- # Create Discourse client for user
267
- client = DiscourseClient (
268
- settings .DISCOURSE_HOST ,
269
- api_username = user .username ,
270
- api_key = settings .DISCOURSE_API_KEY ,
271
- )
284
+ """Call discourse API to check discourse user exists.
285
+ If the user does not exit user_id will be 0.
286
+ """
272
287
273
- # Check user is present in Discourse
288
+ client = _get_client ()
274
289
error , error_message , user_id = get_user (client , user .username )
275
- if user_id == 0 :
276
- return error , error_message , 0
277
-
278
290
return error , error_message , user_id
0 commit comments