1 from __future__
import absolute_import
, division
, print_function
, unicode_literals
12 from backports
import lzma
17 from io
import StringIO
20 from cStringIO
import StringIO
22 from StringIO
import StringIO
24 PY2
= sys
.version_info
[0] == 2
26 def open_compressed_file(filename
):
27 """ Open a file, trying various compression methods if available. """
28 if filename
.endswith('.gz'):
29 return gzip
.open(filename
, 'rt', encoding
='utf-8')
30 elif filename
.endswith('.bz2'):
31 return bz2
.open(filename
, 'rt', encoding
='utf-8')
32 elif filename
.endswith('.xz') or filename
.endswith('.lzma'):
34 return lzma
.open(filename
, 'rt', encoding
='utf-8')
36 raise ImportError("lzma module is not available")
38 return io
.open(filename
, 'r', encoding
='utf-8')
40 def save_compressed_file(data
, filename
):
41 """ Save data to a file, using various compression methods if specified. """
42 if filename
.endswith('.gz'):
43 with gzip
.open(filename
, 'wt', encoding
='utf-8') as file:
45 elif filename
.endswith('.bz2'):
46 with bz2
.open(filename
, 'wt', encoding
='utf-8') as file:
48 elif filename
.endswith('.xz') or filename
.endswith('.lzma'):
50 with lzma
.open(filename
, 'wt', encoding
='utf-8') as file:
53 raise ImportError("lzma module is not available")
55 with io
.open(filename
, 'w', encoding
='utf-8') as file:
59 """ Parse a line in the format 'var: value' and return the key and value. """
60 parts
= line
.split(":", 1)
62 key
= parts
[0].strip()
63 value
= parts
[1].strip()
67 def validate_non_negative_integer(value
, variable_name
, line_number
):
68 """ Validate and convert a value to a non-negative integer. """
70 int_value
= int(value
)
75 raise ValueError("{0} on line {1} should be a non-negative integer, but got '{2}'.".format(variable_name
, line_number
, value
))
77 def parse_file(filename
, validate_only
=False, verbose
=False):
78 with
open_compressed_file(filename
) as file:
79 lines
= file.readlines()
80 return parse_lines(lines
, validate_only
, verbose
)
82 def parse_string(data
, validate_only
=False, verbose
=False):
83 lines
= StringIO(data
).readlines()
84 return parse_lines(lines
, validate_only
, verbose
)
86 def parse_lines(lines
, validate_only
=False, verbose
=False):
88 current_service
= None
90 in_message_list
= False
91 in_message_thread
= False
93 in_message_post
= False
95 in_message_body
= False
96 in_comment_section
= False
97 in_include_service
= False
98 in_include_users
= False
99 in_include_messages
= False
100 in_category_list
= False
101 in_description_body
= False
102 in_include_categories
= False
103 in_categorization_list
= False
107 current_message
= None
108 current_thread
= None
109 current_category
= None
110 categorization_values
= {'Categories': [], 'Forums': []}
111 category_ids
= {'Categories': set(), 'Forums': set()}
114 def parse_include_files(file_list
):
115 included_services
= []
116 for include_file
in file_list
:
117 included_services
.extend(parse_file(include_file
, validate_only
, verbose
))
118 return included_services
120 def parse_include_users(file_list
):
122 for include_file
in file_list
:
123 included_users
= parse_file(include_file
, validate_only
, verbose
)
124 for service
in included_users
:
125 users
.update(service
['Users'])
128 def parse_include_messages(file_list
):
130 for include_file
in file_list
:
131 included_messages
= parse_file(include_file
, validate_only
, verbose
)
132 for service
in included_messages
:
133 messages
.extend(service
['MessageThreads'])
136 def parse_include_categories(file_list
):
138 for include_file
in file_list
:
139 included_categories
= parse_file(include_file
, validate_only
, verbose
)
140 for service
in included_categories
:
141 categories
.extend(service
['Categories'])
145 for line_number
, line
in enumerate(lines
, 1):
147 if line
== "--- Include Service Start ---":
148 in_include_service
= True
151 print("Line {0}: {1} (Starting include service section)".format(line_number
, line
))
153 elif line
== "--- Include Service End ---":
154 in_include_service
= False
156 print("Line {0}: {1} (Ending include service section)".format(line_number
, line
))
157 services
.extend(parse_include_files(include_files
))
159 elif in_include_service
:
160 include_files
.append(line
)
162 print("Line {0}: {1} (Including file for service)".format(line_number
, line
))
164 elif line
== "--- Include Users Start ---":
165 in_include_users
= True
168 print("Line {0}: {1} (Starting include users section)".format(line_number
, line
))
170 elif line
== "--- Include Users End ---":
171 in_include_users
= False
173 print("Line {0}: {1} (Ending include users section)".format(line_number
, line
))
175 current_service
['Users'].update(parse_include_users(include_files
))
177 elif in_include_users
:
178 include_files
.append(line
)
180 print("Line {0}: {1} (Including file for users)".format(line_number
, line
))
182 elif line
== "--- Include Messages Start ---":
183 in_include_messages
= True
186 print("Line {0}: {1} (Starting include messages section)".format(line_number
, line
))
188 elif line
== "--- Include Messages End ---":
189 in_include_messages
= False
191 print("Line {0}: {1} (Ending include messages section)".format(line_number
, line
))
193 current_service
['MessageThreads'].extend(parse_include_messages(include_files
))
195 elif in_include_messages
:
196 include_files
.append(line
)
198 print("Line {0}: {1} (Including file for messages)".format(line_number
, line
))
200 elif line
== "--- Include Categories Start ---":
201 in_include_categories
= True
204 print("Line {0}: {1} (Starting include categories section)".format(line_number
, line
))
206 elif line
== "--- Include Categories End ---":
207 in_include_categories
= False
209 print("Line {0}: {1} (Ending include categories section)".format(line_number
, line
))
211 current_service
['Categories'].extend(parse_include_categories(include_files
))
212 for category
in current_service
['Categories']:
213 kind_split
= category
.get('Kind', '').split(",")
214 category
['Type'] = kind_split
[0].strip()
215 category
['Level'] = kind_split
[1].strip()
216 category_ids
[category
['Type']].add(category
['ID'])
218 elif in_include_categories
:
219 include_files
.append(line
)
221 print("Line {0}: {1} (Including file for categories)".format(line_number
, line
))
223 elif line
== "--- Start Archive Service ---":
224 current_service
= {'Users': {}, 'MessageThreads': [], 'Categories': [], 'Interactions': [], 'Categorization': {}}
226 print("Line {0}: {1} (Starting new archive service)".format(line_number
, line
))
228 elif line
== "--- End Archive Service ---":
229 services
.append(current_service
)
230 current_service
= None
232 print("Line {0}: {1} (Ending archive service)".format(line_number
, line
))
234 elif line
== "--- Start Comment Section ---":
235 in_comment_section
= True
237 print("Line {0}: {1} (Starting comment section)".format(line_number
, line
))
239 elif line
== "--- End Comment Section ---":
240 in_comment_section
= False
242 print("Line {0}: {1} (Ending comment section)".format(line_number
, line
))
244 elif in_comment_section
:
246 print("Line {0}: {1} (Comment)".format(line_number
, line
))
248 elif line
== "--- Start Category List ---":
249 in_category_list
= True
250 current_category
= {}
252 print("Line {0}: {1} (Starting category list)".format(line_number
, line
))
254 elif line
== "--- End Category List ---":
255 in_category_list
= False
257 kind_split
= current_category
.get('Kind', '').split(",")
258 current_category
['Type'] = kind_split
[0].strip()
259 current_category
['Level'] = kind_split
[1].strip()
260 if current_category
['Type'] not in categorization_values
:
261 raise ValueError("Invalid 'Type' value '{0}' on line {1}. Expected one of {2}.".format(current_category
['Type'], line_number
, categorization_values
.keys()))
262 if current_category
['InSub'] != 0 and current_category
['InSub'] not in category_ids
[current_category
['Type']]:
263 raise ValueError("InSub value '{0}' on line {1} does not match any existing ID values.".format(current_category
['InSub'], line_number
))
264 current_service
['Categories'].append(current_category
)
265 category_ids
[current_category
['Type']].add(current_category
['ID'])
266 current_category
= None
268 print("Line {0}: {1} (Ending category list)".format(line_number
, line
))
270 elif line
== "--- Start Categorization List ---":
271 in_categorization_list
= True
272 current_service
['Categorization'] = {}
274 print("Line {0}: {1} (Starting categorization list)".format(line_number
, line
))
276 elif line
== "--- End Categorization List ---":
277 in_categorization_list
= False
279 print("Line {0}: {1} (Ending categorization list)".format(line_number
, line
))
280 categorization_values
= current_service
['Categorization']
282 elif current_service
is not None:
283 key
, value
= parse_line(line
)
285 current_service
['Entry'] = validate_non_negative_integer(value
, "Entry", line_number
)
286 elif key
== "Service":
287 current_service
['Service'] = value
288 elif key
== "Categories":
289 current_service
['Categorization']['Categories'] = [category
.strip() for category
in value
.split(",")]
291 print("Line {0}: Categories set to {1}".format(line_number
, current_service
['Categorization']['Categories']))
292 elif key
== "Forums":
293 current_service
['Categorization']['Forums'] = [forum
.strip() for forum
in value
.split(",")]
295 print("Line {0}: Forums set to {1}".format(line_number
, current_service
['Categorization']['Forums']))
296 elif in_category_list
:
298 current_category
['Kind'] = value
300 current_category
['ID'] = validate_non_negative_integer(value
, "ID", line_number
)
302 current_category
['InSub'] = validate_non_negative_integer(value
, "InSub", line_number
)
303 elif key
== "Headline":
304 current_category
['Headline'] = value
305 elif key
== "Description":
306 current_category
['Description'] = value
307 elif line
== "--- Start User List ---":
310 print("Line {0}: {1} (Starting user list)".format(line_number
, line
))
312 elif line
== "--- End User List ---":
315 print("Line {0}: {1} (Ending user list)".format(line_number
, line
))
317 elif line
== "--- Start User Info ---":
320 print("Line {0}: {1} (Starting user info)".format(line_number
, line
))
322 elif line
== "--- End User Info ---":
326 print("Line {0}: {1} (Ending user info)".format(line_number
, line
))
328 elif line
== "--- Start Message List ---":
329 in_message_list
= True
331 print("Line {0}: {1} (Starting message list)".format(line_number
, line
))
333 elif line
== "--- End Message List ---":
334 in_message_list
= False
336 print("Line {0}: {1} (Ending message list)".format(line_number
, line
))
338 elif line
== "--- Start Message Thread ---":
339 in_message_thread
= True
340 current_thread
= {'Title': '', 'Messages': []}
343 print("Line {0}: {1} (Starting message thread)".format(line_number
, line
))
345 elif line
== "--- End Message Thread ---":
346 in_message_thread
= False
347 current_service
['MessageThreads'].append(current_thread
)
348 current_thread
= None
350 print("Line {0}: {1} (Ending message thread)".format(line_number
, line
))
352 elif line
== "--- Start Message Post ---":
353 in_message_post
= True
356 print("Line {0}: {1} (Starting message post)".format(line_number
, line
))
358 elif line
== "--- End Message Post ---":
359 in_message_post
= False
361 current_thread
['Messages'].append(current_message
)
362 current_message
= None
364 print("Line {0}: {1} (Ending message post)".format(line_number
, line
))
366 elif in_message_list
and key
== "Interactions":
367 current_service
['Interactions'] = [interaction
.strip() for interaction
in value
.split(",")]
369 print("Line {0}: Interactions set to {1}".format(line_number
, current_service
['Interactions']))
371 if in_user_list
and in_user_info
:
373 user_id
= validate_non_negative_integer(value
, "User", line_number
)
374 current_service
['Users'][user_id
] = {'Bio': ""}
376 print("Line {0}: User ID set to {1}".format(line_number
, user_id
))
378 if user_id
is not None:
379 current_service
['Users'][user_id
]['Name'] = value
381 print("Line {0}: Name set to {1}".format(line_number
, value
))
382 elif key
== "Handle":
383 if user_id
is not None:
384 current_service
['Users'][user_id
]['Handle'] = value
386 print("Line {0}: Handle set to {1}".format(line_number
, value
))
387 elif key
== "Location":
388 if user_id
is not None:
389 current_service
['Users'][user_id
]['Location'] = value
391 print("Line {0}: Location set to {1}".format(line_number
, value
))
392 elif key
== "Joined":
393 if user_id
is not None:
394 current_service
['Users'][user_id
]['Joined'] = value
396 print("Line {0}: Joined date set to {1}".format(line_number
, value
))
397 elif key
== "Birthday":
398 if user_id
is not None:
399 current_service
['Users'][user_id
]['Birthday'] = value
401 print("Line {0}: Birthday set to {1}".format(line_number
, value
))
402 elif line
== "--- Start Bio Body ---":
403 if user_id
is not None:
407 print("Line {0}: Starting bio body".format(line_number
))
408 elif line
== "--- End Bio Body ---":
409 if user_id
is not None and current_bio
is not None:
410 current_service
['Users'][user_id
]['Bio'] = "\n".join(current_bio
)
414 print("Line {0}: Ending bio body".format(line_number
))
415 elif in_bio_body
and current_bio
is not None:
416 current_bio
.append(line
)
418 print("Line {0}: Adding to bio body: {1}".format(line_number
, line
))
419 elif in_message_list
and in_message_thread
:
421 current_thread
['Thread'] = validate_non_negative_integer(value
, "Thread", line_number
)
423 print("Line {0}: Thread ID set to {1}".format(line_number
, value
))
424 elif key
== "Category":
425 current_thread
['Category'] = [category
.strip() for category
in value
.split(",")]
427 print("Line {0}: Category set to {1}".format(line_number
, current_thread
['Category']))
429 current_thread
['Forum'] = [forum
.strip() for forum
in value
.split(",")]
431 print("Line {0}: Forum set to {1}".format(line_number
, current_thread
['Forum']))
433 current_thread
['Title'] = value
435 print("Line {0}: Title set to {1}".format(line_number
, value
))
436 elif key
== "Author":
437 current_message
['Author'] = value
439 print("Line {0}: Author set to {1}".format(line_number
, value
))
441 current_message
['Time'] = value
443 print("Line {0}: Time set to {1}".format(line_number
, value
))
445 current_message
['Date'] = value
447 print("Line {0}: Date set to {1}".format(line_number
, value
))
450 if message_type
not in current_service
['Interactions']:
451 raise ValueError("Unexpected message type '{0}' found on line {1}. Expected one of {2}".format(message_type
, line_number
, current_service
['Interactions']))
452 current_message
['Type'] = message_type
454 print("Line {0}: Type set to {1}".format(line_number
, message_type
))
456 post_value
= validate_non_negative_integer(value
, "Post", line_number
)
457 current_message
['Post'] = post_value
458 if 'post_ids' not in current_thread
:
459 current_thread
['post_ids'] = set()
460 current_thread
['post_ids'].add(post_value
)
462 print("Line {0}: Post ID set to {1}".format(line_number
, post_value
))
463 elif key
== "Nested":
464 nested_value
= validate_non_negative_integer(value
, "Nested", line_number
)
465 if nested_value
!= 0 and nested_value
not in current_thread
.get('post_ids', set()):
467 "Nested value '{0}' on line {1} does not match any existing Post values in the current thread. Existing Post IDs: {2}".format(
468 nested_value
, line_number
, list(current_thread
.get('post_ids', set())))
470 current_message
['Nested'] = nested_value
472 print("Line {0}: Nested set to {1}".format(line_number
, nested_value
))
473 elif line
== "--- Start Message Body ---":
474 if current_message
is not None:
475 current_message
['Message'] = []
476 in_message_body
= True
478 print("Line {0}: Starting message body".format(line_number
))
479 elif line
== "--- End Message Body ---":
480 if current_message
is not None and 'Message' in current_message
:
481 current_message
['Message'] = "\n".join(current_message
['Message'])
482 in_message_body
= False
484 print("Line {0}: Ending message body".format(line_number
))
485 elif in_message_body
and current_message
is not None and 'Message' in current_message
:
486 current_message
['Message'].append(line
)
488 print("Line {0}: Adding to message body: {1}".format(line_number
, line
))
489 except Exception as e
:
491 return False, "Error: {0}".format(str(e
)), lines
[line_number
- 1]
500 def display_services(services
):
501 for service
in services
:
502 print("Service Entry: {0}".format(service
['Entry']))
503 print("Service: {0}".format(service
['Service']))
504 print("Interactions: {0}".format(', '.join(service
['Interactions'])))
505 if 'Categorization' in service
and service
['Categorization']:
506 for category_type
, category_levels
in service
['Categorization'].items():
507 print("{0}: {1}".format(category_type
, ', '.join(category_levels
)))
508 print("Category List:")
509 for category
in service
['Categories']:
510 kind_split
= category
.get('Kind', '').split(",")
511 category
['Type'] = kind_split
[0].strip()
512 category
['Level'] = kind_split
[1].strip()
513 print(" Type: {0}, Level: {1}".format(category
['Type'], category
['Level']))
514 print(" ID: {0}".format(category
['ID']))
515 print(" InSub: {0}".format(category
['InSub']))
516 print(" Headline: {0}".format(category
['Headline']))
517 print(" Description: {0}".format(category
['Description'].strip()))
520 for user_id
, user_info
in service
['Users'].items():
521 print(" User ID: {0}".format(user_id
))
522 print(" Name: {0}".format(user_info
['Name']))
523 print(" Handle: {0}".format(user_info
['Handle']))
524 print(" Location: {0}".format(user_info
.get('Location', '')))
525 print(" Joined: {0}".format(user_info
.get('Joined', '')))
526 print(" Birthday: {0}".format(user_info
.get('Birthday', '')))
527 print(" Bio: {0}".format(user_info
.get('Bio', '').strip()))
529 print("Message Threads:")
530 for idx
, thread
in enumerate(service
['MessageThreads']):
531 print(" --- Message Thread {0} ---".format(idx
+1))
533 print(" Title: {0}".format(thread
['Title']))
534 if 'Category' in thread
:
535 print(" Category: {0}".format(', '.join(thread
['Category'])))
536 if 'Forum' in thread
:
537 print(" Forum: {0}".format(', '.join(thread
['Forum'])))
538 for message
in thread
['Messages']:
539 print(" {0} ({1} on {2}): [{3}] Post ID: {4} Nested: {5}".format(
540 message
['Author'], message
['Time'], message
['Date'], message
['Type'], message
['Post'], message
['Nested']))
541 print(" {0}".format(message
['Message'].strip()))
544 def to_json(services
):
545 """ Convert the services data structure to JSON """
546 return json
.dumps(services
, indent
=2)
548 def from_json(json_str
):
549 """ Convert a JSON string back to the services data structure """
550 return json
.loads(json_str
)
552 def load_from_json_file(json_filename
):
553 """ Load the services data structure from a JSON file """
554 with
open_compressed_file(json_filename
) as file:
555 return json
.load(file)
557 def save_to_json_file(services
, json_filename
):
558 """ Save the services data structure to a JSON file """
559 json_data
= json
.dumps(services
, indent
=2)
560 save_compressed_file(json_data
, json_filename
)
562 def services_to_string(services
, line_ending
="lf"):
563 """ Convert the services data structure back to the original text format """
565 for service
in services
:
566 lines
.append("--- Start Archive Service ---")
567 lines
.append("Entry: {0}".format(service
['Entry']))
568 lines
.append("Service: {0}".format(service
['Service']))
570 lines
.append("--- Start User List ---")
571 for user_id
, user_info
in service
['Users'].items():
572 lines
.append("--- Start User Info ---")
573 lines
.append("User: {0}".format(user_id
))
574 lines
.append("Name: {0}".format(user_info
['Name']))
575 lines
.append("Handle: {0}".format(user_info
['Handle']))
576 if 'Location' in user_info
:
577 lines
.append("Location: {0}".format(user_info
['Location']))
578 if 'Joined' in user_info
:
579 lines
.append("Joined: {0}".format(user_info
['Joined']))
580 if 'Birthday' in user_info
:
581 lines
.append("Birthday: {0}".format(user_info
['Birthday']))
582 if 'Bio' in user_info
:
584 lines
.append("--- Start Bio Body ---")
585 lines
.extend(user_info
['Bio'].split("\n"))
586 lines
.append("--- End Bio Body ---")
587 lines
.append("--- End User Info ---")
588 lines
.append("--- End User List ---")
590 if 'Categorization' in service
and service
['Categorization']:
591 lines
.append("--- Start Categorization List ---")
592 for category_type
, category_levels
in service
['Categorization'].items():
593 lines
.append("{0}: {1}".format(category_type
, ', '.join(category_levels
)))
594 lines
.append("--- End Categorization List ---")
596 if 'Categories' in service
and service
['Categories']:
597 for category
in service
['Categories']:
598 lines
.append("--- Start Category List ---")
599 lines
.append("Kind: {0}, {1}".format(category
['Type'], category
['Level']))
600 lines
.append("ID: {0}".format(category
['ID']))
601 lines
.append("InSub: {0}".format(category
['InSub']))
602 lines
.append("Headline: {0}".format(category
['Headline']))
603 lines
.append("Description: {0}".format(category
['Description']))
604 lines
.append("--- End Category List ---")
606 lines
.append("--- Start Message List ---")
607 lines
.append("Interactions: {0}".format(', '.join(service
['Interactions'])))
608 for thread
in service
['MessageThreads']:
609 lines
.append("--- Start Message Thread ---")
610 lines
.append("Thread: {0}".format(thread
['Thread']))
611 if 'Category' in thread
:
612 lines
.append("Category: {0}".format(', '.join(thread
['Category'])))
613 if 'Forum' in thread
:
614 lines
.append("Forum: {0}".format(', '.join(thread
['Forum'])))
615 if 'Title' in thread
:
616 lines
.append("Title: {0}".format(thread
['Title']))
617 for message
in thread
['Messages']:
618 lines
.append("--- Start Message Post ---")
619 lines
.append("Author: {0}".format(message
['Author']))
620 lines
.append("Time: {0}".format(message
['Time']))
621 lines
.append("Date: {0}".format(message
['Date']))
622 lines
.append("Type: {0}".format(message
['Type']))
623 lines
.append("Post: {0}".format(message
['Post']))
624 lines
.append("Nested: {0}".format(message
['Nested']))
625 lines
.append("Message:")
626 lines
.append("--- Start Message Body ---")
627 lines
.extend(message
['Message'].split("\n"))
628 lines
.append("--- End Message Body ---")
629 lines
.append("--- End Message Post ---")
630 lines
.append("--- End Message Thread ---")
631 lines
.append("--- End Message List ---")
633 lines
.append("--- End Archive Service ---")
635 line_sep
= {"lf": "\n", "cr": "\r", "crlf": "\r\n"}
636 return line_sep
.get(line_ending
, "\n").join(lines
)
638 def save_services_to_file(services
, filename
, line_ending
="lf"):
639 """ Save the services data structure to a file in the original text format """
640 data
= services_to_string(services
, line_ending
)
641 save_compressed_file(data
, filename
)
643 def init_empty_service(entry
, service_name
):
644 """ Initialize an empty service structure """
647 'Service': service_name
,
649 'MessageThreads': [],
655 def add_user(service
, user_id
, name
, handle
, location
='', joined
='', birthday
='', bio
=''):
656 """ Add a user to the service """
657 service
['Users'][user_id
] = {
660 'Location': location
,
662 'Birthday': birthday
,
666 def remove_user(service
, user_id
):
667 """ Remove a user from the service """
668 if user_id
in service
['Users']:
669 del service
['Users'][user_id
]
671 def add_category(service
, kind
, category_type
, category_level
, category_id
, insub
, headline
, description
):
672 """ Add a category to the service """
675 'Level': category_level
,
678 'Headline': headline
,
679 'Description': description
681 service
['Categories'].append(category
)
682 if category_type
not in service
['Categorization']:
683 service
['Categorization'][category_type
] = []
684 if category_level
not in service
['Categorization'][category_type
]:
685 service
['Categorization'][category_type
].append(category_level
)
687 def remove_category(service
, category_id
):
688 """ Remove a category from the service """
689 service
['Categories'] = [category
for category
in service
['Categories'] if category
['ID'] != category_id
]
691 def add_message_thread(service
, thread_id
, title
='', category
='', forum
=''):
692 """ Add a message thread to the service """
696 'Category': category
.split(',') if category
else [],
697 'Forum': forum
.split(',') if forum
else [],
700 service
['MessageThreads'].append(thread
)
702 def remove_message_thread(service
, thread_id
):
703 """ Remove a message thread from the service """
704 service
['MessageThreads'] = [thread
for thread
in service
['MessageThreads'] if thread
['Thread'] != thread_id
]
706 def add_message_post(service
, thread_id
, author
, time
, date
, msg_type
, post_id
, nested
, message
):
707 """ Add a message post to a thread in the service """
708 for thread
in service
['MessageThreads']:
709 if thread
['Thread'] == thread_id
:
719 thread
['Messages'].append(post
)
721 raise ValueError("Thread ID {0} not found in service".format(thread_id
))
723 def remove_message_post(service
, thread_id
, post_id
):
724 """ Remove a message post from a thread in the service """
725 for thread
in service
['MessageThreads']:
726 if thread
['Thread'] == thread_id
:
727 thread
['Messages'] = [post
for post
in thread
['Messages'] if post
['Post'] != post_id
]
729 raise ValueError("Thread ID {0} not found in service".format(thread_id
))
731 def add_service(services
, entry
, service_name
):
732 """ Add a new service to the list of services """
733 new_service
= init_empty_service(entry
, service_name
)
734 services
.append(new_service
)
737 def remove_service(services
, entry
):
738 """ Remove an existing service from the list of services """
739 services
[:] = [service
for service
in services
if service
['Entry'] != entry
]
741 # Sample code to test the functions
742 if __name__
== "__main__":
743 # Initialize an empty list of services
747 new_service
= add_service(services
, entry
=1, service_name
="Message Board")
750 add_user(new_service
, user_id
=1, name
="Cool Dude 2k", handle
="@cooldude2k", location
="Somewhere", joined
="Jul 1, 2024", birthday
="Jul 1, 1987", bio
="I'm just a very cool dude! ^_^")
751 add_user(new_service
, user_id
=2, name
="Kazuki Suzuki", handle
="@kazuki.suzuki", location
="Anywhere", joined
="Jul 1, 2024", birthday
="Jun 1, 1987", bio
="Hello it's just me Kazuki. :P")
754 add_category(new_service
, kind
="Categories", category_type
="Category", category_level
="Main Category", category_id
=1, insub
=0, headline
="Game Maker 2k", description
="Just talk about anything.")
755 add_category(new_service
, kind
="Forums", category_type
="Forum", category_level
="Main Forum", category_id
=1, insub
=0, headline
="General Discussion", description
="Just talk about anything.")
758 add_message_thread(new_service
, thread_id
=1, title
="Hello, World!", category
="Game Maker 2k", forum
="General Discussion")
761 add_message_post(new_service
, thread_id
=1, author
="@kazuki.suzuki", time
="8:00 AM", date
="Jul 1, 2024", msg_type
="Post", post_id
=1, nested
=0, message
="Hello, World! ^_^")
762 add_message_post(new_service
, thread_id
=1, author
="@cooldude2k", time
="10:00 AM", date
="Jul 1, 2024", msg_type
="Reply", post_id
=2, nested
=1, message
="Why did you say 'Hello, World!' O_o")
763 add_message_post(new_service
, thread_id
=1, author
="@kazuki.suzuki", time
="12:00 PM", date
="Jul 1, 2024", msg_type
="Reply", post_id
=3, nested
=2, message
="I don't know.\nI thought it would be cool. ^_^")
764 add_message_post(new_service
, thread_id
=1, author
="@cooldude2k", time
="2:00 PM", date
="Jul 1, 2024", msg_type
="Reply", post_id
=4, nested
=3, message
="What ever dude! <_<")
766 # Add another service
767 another_service
= add_service(services
, entry
=2, service_name
="Another Board")
769 # Display the services
770 display_services(services
)
773 remove_service(services
, entry
=1)
775 # Display the services again
776 display_services(services
)