Skip to content

Commit 819f5c4

Browse files
committed
📤 move helper methods to separate files
1 parent 52c1805 commit 819f5c4

File tree

11 files changed

+668
-621
lines changed

11 files changed

+668
-621
lines changed

src/moodle_to_vikwikiquiz/helpers.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from os import system
2+
from pathlib import Path
3+
from time import sleep
4+
5+
from send2trash import send2trash # type: ignore
6+
7+
8+
def clear_terminal() -> None:
9+
system("clear||cls")
10+
11+
12+
def wait_for_pastebot_to_recognize_copy() -> None:
13+
print("Waiting 2 seconds for Pastebot to recognize it...")
14+
sleep(2)
15+
print("...done!")
16+
17+
18+
def remove_uploaded_files(folder: Path) -> None:
19+
send2trash(folder)

src/moodle_to_vikwikiquiz/main.py

Lines changed: 2 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
from argparse import ArgumentParser, Namespace
22
import logging
33
from pathlib import Path
4-
from platform import system
54
from sys import version_info
6-
from time import sleep
7-
from urllib.parse import quote, urlencode
8-
from webbrowser import open_new_tab
9-
10-
# future: delete the comment below when stubs for the package below are available
11-
from pyperclip import copy # type: ignore
12-
from send2trash import send2trash # type: ignore
135

6+
from .wiki import create_article, get_article_instructions, log_in_to_wiki # type: ignore
147
from .quiz.illustrations.state_of_illustrations import StateOfIllustrations # type: ignore
158
from .quiz.grading_types import GradingType # type: ignore
169
from .quiz.quiz import Quiz # type: ignore
17-
from .quiz.quiz_helpers import clear_terminal # type: ignore
10+
from .helpers import clear_terminal, wait_for_pastebot_to_recognize_copy # type: ignore
1811

1912

2013
def main() -> None:
@@ -69,108 +62,6 @@ def main() -> None:
6962
logging.getLogger(__name__).debug("Program finished!")
7063

7164

72-
def get_article_instructions(
73-
quiz: Quiz, wiki_domain: str
74-
) -> tuple[str, dict[str, str], dict[str, str], dict[str, str]]:
75-
wikitext_instructions = """
76-
<!-- További teendőid (ebben a sorrendben):
77-
• e komment feletti sorba illeszd be a vágólapodra másolt tartalmat
78-
• kattints az 'Előnézet megtekintése' gombra"""
79-
operating_system = system()
80-
wiki_modifier_keys = {
81-
"Darwin": "Control-Option",
82-
"Linux": "Alt-Shift",
83-
"Windows": "Alt-Shift",
84-
}
85-
wiki_editor_keys = {"Show preview": "P", "Publish page": "S"}
86-
if operating_system == "Darwin" or operating_system == "Linux":
87-
wikitext_instructions += f" ({wiki_modifier_keys[operating_system]}-{wiki_editor_keys["Show preview"]})"
88-
wikitext_instructions += """
89-
• javítsd a helyesírást és a formázást (ha szükséges), különös tekintettel a képletekre"""
90-
match quiz.state_of_illustrations:
91-
case StateOfIllustrations.YesAndAvailable:
92-
upload_directory = quiz.get_illustrations_ready_for_upload()
93-
go_to_folder_keyboard_shortcuts = {
94-
"Darwin": "Command-Shift-G",
95-
"Linux": "Ctrl-L",
96-
"Windows": "Ctrl-L",
97-
}
98-
print(
99-
f"""The batch upload page of the wiki will now be opened. After that, please...
100-
• click on 'Fájlok kiválasztása...'"""
101-
)
102-
if operating_system == "Darwin" or operating_system == "Linux":
103-
copy(str(upload_directory))
104-
print(
105-
f""" • press {go_to_folder_keyboard_shortcuts[operating_system]}
106-
• paste the content of the clipboard
107-
• press Enter"""
108-
)
109-
else:
110-
print(" • open the following folder: " + str(upload_directory))
111-
print(
112-
""" • select all files in the folder
113-
• click on 'Upload'
114-
• return here."""
115-
)
116-
input("\nPlease press Enter then follow these instructions...")
117-
open_new_tab(
118-
f"{wiki_domain}/Speciális:TömegesFeltöltés/moodle-to-vikwikiquiz"
119-
)
120-
input("Please press Enter if you're done with uploading...")
121-
if upload_directory:
122-
remove_uploaded_files(upload_directory)
123-
clear_terminal()
124-
125-
print("Great! I've deleted the uploaded files from your disk.\n")
126-
case StateOfIllustrations.YesButUnavailable:
127-
wikitext_instructions += """
128-
• töltsd fel kézzel, egyesével a piros linkekkel formázott illusztrációkat
129-
• másold ki a megfelelő "Fájl:" wikitext után található generált fájlnevet
130-
• kattints a szerkesztő eszköztárában található 'Képek és médiafájlok' gombra
131-
• töltsd fel az illusztrációt"""
132-
case StateOfIllustrations.Nil:
133-
pass
134-
wikitext_instructions += """
135-
• töröld ezt a kommentet
136-
• kattints a 'Lap mentése' gombra"""
137-
if operating_system == "Darwin" or operating_system == "Linux":
138-
wikitext_instructions += f" ({wiki_modifier_keys[operating_system]}-{wiki_editor_keys["Publish page"]})"
139-
wikitext_instructions += """
140-
-->"""
141-
parameters_for_opening_edit = {
142-
"action": "edit",
143-
"summary": "Kvíz bővítése "
144-
"a https://github.com/gy-mate/moodle-to-vikwikiquiz segítségével importált Moodle-kvíz(ek)ből",
145-
"preload": "Sablon:Előbetöltés",
146-
"preloadparams[]": wikitext_instructions,
147-
}
148-
clear_terminal()
149-
return (
150-
operating_system,
151-
parameters_for_opening_edit,
152-
wiki_editor_keys,
153-
wiki_modifier_keys,
154-
)
155-
156-
157-
def log_in_to_wiki(wiki_domain: str) -> None:
158-
input(
159-
"""Let's log in to the wiki! Please...
160-
• if you see the login page, log in
161-
• when you see the main page of the wiki, return here.
162-
163-
Please press Enter to open the login page..."""
164-
)
165-
open_new_tab(f"{wiki_domain}/index.php?title=Speciális:Belépés")
166-
input("Please press Enter if you've logged in...")
167-
clear_terminal()
168-
169-
170-
def remove_uploaded_files(folder: Path) -> None:
171-
send2trash(folder)
172-
173-
17465
def parse_arguments() -> Namespace:
17566
parser = ArgumentParser(
17667
"Convert graded and downloaded Moodle quizzes to a vik.viki quiz wikitext."
@@ -258,102 +149,5 @@ def get_grading() -> GradingType:
258149
clear_terminal()
259150

260151

261-
def create_article(
262-
args: Namespace,
263-
parameters_for_opening_edit: dict[str, str],
264-
quiz_title: str,
265-
quiz_wikitext: str,
266-
wiki_domain: str,
267-
wiki_modifier_keys: dict[str, str],
268-
wiki_editor_keys: dict[str, str],
269-
operating_system: str,
270-
) -> None:
271-
if args.new:
272-
parameters_for_opening_edit_with_paste = parameters_for_opening_edit.copy()
273-
parameters_for_opening_edit_with_paste.update(
274-
{
275-
"preload": "Sablon:Előbetöltés",
276-
"preloadparams[]": quiz_wikitext,
277-
}
278-
)
279-
parameters_for_opening_edit_with_paste["summary"] = (
280-
parameters_for_opening_edit_with_paste["summary"].replace(
281-
"bővítése", "létrehozása"
282-
)
283-
)
284-
url = f"{wiki_domain}/{quiz_title}?{urlencode(parameters_for_opening_edit_with_paste)}"
285-
if len(url) < 2048:
286-
return open_article_paste_text(args, quiz_wikitext, url)
287-
else:
288-
open_article(args, parameters_for_opening_edit, url)
289-
else:
290-
del parameters_for_opening_edit["preload"]
291-
del parameters_for_opening_edit["preloadparams[]"]
292-
copy(quiz_wikitext)
293-
print("\nThe wikitext of the quiz has been copied to the clipboard!")
294-
url = f"{wiki_domain}/{quote(quiz_title)}?{urlencode(parameters_for_opening_edit)}"
295-
if not args.new:
296-
print(
297-
f"""
298-
The existing article will now be opened for editing. After that, please...
299-
• scroll to the bottom of the wikitext in the editor
300-
• add a new line
301-
• paste the content of the clipboard in that line
302-
• click on the 'Előnézet megtekintése' button ({wiki_modifier_keys[operating_system]}-{wiki_editor_keys["Show preview"]})
303-
• correct the spelling and formatting (if necessary), especially the formulas
304-
• click on the 'Lap mentése' button ({wiki_modifier_keys[operating_system]}-{wiki_editor_keys["Publish page"]})"""
305-
)
306-
input("\nPlease press Enter then follow these instructions...")
307-
open_new_tab(url)
308-
print(
309-
"\nThe edit page of the quiz article has been opened in your browser!", end=" "
310-
)
311-
if args.new:
312-
print("Please follow the instructions there.")
313-
314-
315-
def open_article_paste_text(args: Namespace, quiz_wikitext: str, url: str) -> None:
316-
copy(quiz_wikitext)
317-
print(
318-
"\nThe wikitext of the quiz has been copied to the clipboard! "
319-
"This will be overwritten but you may recall it later if you use an app like Pastebot."
320-
)
321-
wait_for_pastebot_to_recognize_copy()
322-
if args.verbose:
323-
copy(url)
324-
print("The URL has been copied to the clipboard!")
325-
open_new_tab(url)
326-
print(
327-
"\nThe edit page of the new quiz article has been opened in your browser with the wikitext pre-filled! "
328-
"Please upload illustrations manually, if there are any."
329-
)
330-
return
331-
332-
333-
def open_article(
334-
args: Namespace, parameters_for_opening_edit: dict[str, str], url: str
335-
) -> None:
336-
logging.getLogger(__name__).warning(
337-
"I can't create the article automatically "
338-
"because the URL would be too long for some browsers (or the server)."
339-
)
340-
if args.verbose:
341-
copy(url)
342-
print(
343-
"\nThis URL has been copied to the clipboard! "
344-
"It will be overwritten but you may recall it later if you use an app like Pastebot."
345-
)
346-
wait_for_pastebot_to_recognize_copy()
347-
parameters_for_opening_edit["summary"] = parameters_for_opening_edit[
348-
"summary"
349-
].replace("bővítése", "létrehozása")
350-
351-
352-
def wait_for_pastebot_to_recognize_copy() -> None:
353-
print("Waiting 2 seconds for Pastebot to recognize it...")
354-
sleep(2)
355-
print("...done!")
356-
357-
358152
if __name__ == "__main__":
359153
main()
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from re import sub
2+
from uuid import uuid4
3+
4+
# noinspection PyPackageRequirements
5+
from pylatexenc.latexencode import unicode_to_latex # type: ignore
6+
7+
from .illustrations.illustration import Illustration # type: ignore
8+
from .questions.helpers import format_latex_as_wikitext # type: ignore
9+
from .quiz_element import QuizElement # type: ignore
10+
from .illustrations.state_of_illustrations import StateOfIllustrations # type: ignore
11+
from .questions.question import Question # type: ignore
12+
from .questions.question_types import QuestionType # type: ignore
13+
14+
15+
def prettify(text: str) -> str:
16+
text = strip_whitespaces(text)
17+
text = format_latex_as_wikitext(text)
18+
return text
19+
20+
21+
def strip_whitespaces(text: str) -> str:
22+
text = text.strip("., \n")
23+
text = sub(r" \n|\r\n|\s{2}", " ", text)
24+
return text
25+
26+
27+
def truncate_filename(element_text: str, extension: str, quiz_name: str) -> str:
28+
number_of_element_text_words = 5
29+
while number_of_element_text_words > 1:
30+
split_element_text = element_text.split()
31+
split_truncated_element_text = " ".join(
32+
split_element_text[:number_of_element_text_words]
33+
)
34+
upload_filename = create_upload_filename(
35+
quiz_name, split_truncated_element_text + "…", extension
36+
)
37+
if not filename_too_long(upload_filename):
38+
return upload_filename
39+
number_of_element_text_words -= 1
40+
41+
# noinspection PyUnboundLocalVariable
42+
split_truncated_element_text = split_truncated_element_text[:15]
43+
upload_filename = create_upload_filename(
44+
quiz_name, split_truncated_element_text + "…", extension
45+
)
46+
return upload_filename
47+
48+
49+
def filename_too_long(upload_filename) -> bool:
50+
return len(upload_filename) > 100
51+
52+
53+
def create_upload_filename(
54+
quiz_name: str, name_of_illustration: str, extension: str, make_unique: bool = False
55+
) -> str:
56+
upload_filename = f'"{name_of_illustration}"'
57+
if make_unique:
58+
random_hash = uuid4().hex[:6]
59+
upload_filename += f" – válaszlehetőség {random_hash}"
60+
upload_filename += f" ({quiz_name}){extension}"
61+
return upload_filename
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from pathlib import Path
2+
from urllib.parse import unquote, urlparse
3+
4+
from bs4 import Tag
5+
6+
from ..helpers import create_upload_filename, filename_too_long, truncate_filename # type: ignore
7+
from .illustration import Illustration # type: ignore
8+
from .state_of_illustrations import StateOfIllustrations # type: ignore
9+
from ..questions.answers.answer import Answer # type: ignore
10+
from ..questions.question import Question # type: ignore
11+
from ..quiz_element import QuizElement # type: ignore
12+
13+
14+
def get_element_illustration(
15+
tag: Tag,
16+
element_text: str,
17+
quiz_name: str,
18+
element: QuizElement,
19+
state_of_illustrations: StateOfIllustrations,
20+
current_folder: Path,
21+
question_name: str | None = None,
22+
) -> Illustration | None:
23+
if image := tag.find("img"):
24+
assert isinstance(image, Tag)
25+
illustration_url = image["src"]
26+
assert isinstance(illustration_url, str)
27+
illustration_url_parsed = urlparse(illustration_url)
28+
illustration_url_parsed = illustration_url_parsed._replace(query="")
29+
illustration_url_string = illustration_url_parsed.geturl()
30+
illustration_path_string = unquote(illustration_url_string)
31+
illustration_path = Path(illustration_path_string)
32+
original_file_path_string = current_folder / illustration_path
33+
original_file_path = Path(original_file_path_string)
34+
extension = original_file_path.suffix
35+
36+
if element is Question:
37+
illustration_size = 500
38+
elif element is Answer:
39+
illustration_size = 250
40+
else:
41+
raise ValueError(f"Unexpected QuizElement type: {element}!")
42+
43+
if element_text == "":
44+
assert question_name
45+
max_question_name_length = 15
46+
if len(question_name) > max_question_name_length:
47+
question_name = f"{question_name[:max_question_name_length]}…"
48+
upload_filename = create_upload_filename(
49+
quiz_name,
50+
question_name,
51+
extension,
52+
make_unique=True,
53+
)
54+
else:
55+
upload_filename = create_upload_filename(quiz_name, element_text, extension)
56+
if filename_too_long(upload_filename):
57+
upload_filename = truncate_filename(element_text, extension, quiz_name)
58+
59+
return Illustration(
60+
upload_filename=upload_filename,
61+
size_in_pixels=illustration_size,
62+
state_of_illustrations=state_of_illustrations,
63+
original_file_path=original_file_path,
64+
)
65+
else:
66+
return None

src/moodle_to_vikwikiquiz/quiz/questions/answer.py renamed to src/moodle_to_vikwikiquiz/quiz/questions/answers/answer.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
from ..illustrations.illustration import Illustration # type: ignore
2-
from ..quiz_element import QuizElement # type: ignore
3-
from ..illustrations.state_of_illustrations import StateOfIllustrations # type: ignore
1+
from ...illustrations.illustration import Illustration # type: ignore
2+
from ...quiz_element import QuizElement # type: ignore
43

54

65
class Answer(QuizElement):

0 commit comments

Comments
 (0)