瀏覽代碼

feat: 完善基本操作

SongZihuan 3 年之前
父節點
當前提交
61ed7ebb03
共有 3 個文件被更改,包括 120 次插入21 次删除
  1. 61 2
      app/test.py
  2. 28 12
      core/db.py
  3. 31 7
      templates/test.html

+ 61 - 2
app/test.py

@@ -1,6 +1,9 @@
-from flask import blueprints, render_template
+from flask import blueprints, render_template, current_app, abort, redirect, url_for, flash, make_response
 from flask_login import current_user, login_required
 from .user import UserWordDataBase
+from itsdangerous import URLSafeTimedSerializer
+from itsdangerous.exc import BadData
+
 
 test = blueprints.Blueprint("test", __name__)
 
@@ -12,4 +15,60 @@ def question():
     word = user.rand_word()
     if word is None:
         return render_template("not_word.html")
-    return render_template("test.html", word=word, len=len)  # 需要使用len函数
+    serializer = URLSafeTimedSerializer(current_app.config["SECRET_KEY"])
+    word_id = serializer.dumps({"word": word.name})
+    return render_template("test.html", word=word, len=len, word_id=word_id)  # 需要使用len函数
+
+
+@test.route("/right/<string:word_id>")
+@login_required
+def right(word_id: str):
+    serializer = URLSafeTimedSerializer(current_app.config["SECRET_KEY"])
+    try:
+        word: dict = serializer.loads(word_id, max_age=120)  # 120s内生效
+        user: UserWordDataBase = current_user
+        user.right_word(word["word"])
+    except (BadData, KeyError):
+        abort(404)
+    return redirect(url_for("test.question"))
+
+
+@test.route("/wrong/<string:word_id>")
+@login_required
+def wrong(word_id: str):
+    serializer = URLSafeTimedSerializer(current_app.config["SECRET_KEY"])
+    try:
+        word: dict = serializer.loads(word_id, max_age=120)  # 120s内生效
+        user: UserWordDataBase = current_user
+        user.wrong_word(word["word"])
+    except (BadData, KeyError):
+        abort(404)
+    return redirect(url_for("test.question"))
+
+
+@test.route("/delete/<string:word>")
+@login_required
+def delete(word: str):
+    user: UserWordDataBase = current_user
+    user.delete_txt(word)
+    flash(f"Word '{word}' is deleted.")
+    return redirect(url_for("test.question"))
+
+
+@test.route("/download/<string:word>")
+@login_required
+def download(word: str):
+    user: UserWordDataBase = current_user
+    w = user.find_word(word, False)
+    if w is None:
+        abort(404)
+    w_str = f"{w.name}\n"
+    for i in w.comment:
+        comment = w.comment[i]
+        w_str += f"  {comment.part}\n  {comment.english}\n  {comment.chinese}\n"
+        for a in comment.eg:
+            e, c = a.split("##")
+            w_str += f"    {e}\n    {c}\n"
+    response = make_response(w_str)
+    response.headers["Content-Disposition"] = f"attachment;filename={word}.henglish.txt"
+    return response

+ 28 - 12
core/db.py

@@ -178,14 +178,16 @@ class WordDatabase(DataBase):
             w.add_comment(c)
         return w
 
-    def find_word(self, q: str) -> Optional[word.Word]:
+    def find_word(self, q: str, search: bool = True) -> Optional[word.Word]:
         res = self.search(columns=["id", "word", "part", "english", "chinese", "eg"],
                           table="Word",
                           where=f"LOWER(word)='{q.lower()}'")
         if res is None:
             res = []
         if len(res) <= 0:
-            return self.__add_word(q)
+            if search:
+                return self.__add_word(q)
+            return None
         self.__logger.debug(f"Find word (not add) {q}")
         return self.__make_word(q, res)
 
@@ -210,7 +212,7 @@ class WordDatabase(DataBase):
         word_list = self.word_pattern.findall(line)
         for w in word_list:
             try:
-                if self.find_word(w) is None:
+                if self.find_word(w, True) is None:
                     self.__logger.debug(f"update word {w} fail")
                     response.add_error(w)
                 else:
@@ -283,18 +285,32 @@ class WordDatabase(DataBase):
         cur = self.delete(table="Word")
         return cur[1].rowcount
 
+    def right_word(self, w: str):
+        res = self.search(columns=["MIN(box)"], table="Word", where=f"word='{w}'")
+        if len(res) == 0:
+            return False
+        box = res[0][0]
+        if box != 5:
+            box += 1
+            self.update(table="Word", kw={"box": f"{box}"}, where=f"word='{w}'")
+        return True
+
+    def wrong_word(self, w: str):
+        self.update(table="Word", kw={"box": "1"}, where=f"word='{w}'")
+        return True
+
     def rand_word(self):
-        r = random.randint(0, 16)
+        r = random.randint(0, 15)
         if r < 5:
-            box = 2
+            box = 2  # 5
         elif r < 9:
-            box = 3
+            box = 3  # 4
         elif r < 12:
-            box = 4
+            box = 4  # 3
         elif r < 14:
-            box = 5
+            box = 5  # 2
         else:
-            box = 6
+            box = 6  # 1
         # box 的概率比分别为:5:4:3:2:1
 
         count = 0
@@ -307,7 +323,7 @@ class WordDatabase(DataBase):
                     double_check = True
                     box = 6
             box -= 1
-            count = self.search(columns=["COUNT(ID)"], table="Word", where=f"box={box}")[0][0]
-        get = self.search(columns=["word"], table="Word", where=f"box={box}", limit=1, offset=random.randint(0, count))[0][0]
+            count = self.search(columns=["COUNT(ID)"], table="Word", where=f"box<={box}")[0][0]
+        get = self.search(columns=["word"], table="Word", where=f"box<={box}", limit=1, offset=random.randint(0, count - 1))[0][0]
         self.__logger.debug(f"Rand word {self.dict_name} from box: {box} count: {count} get: {get}")
-        return self.find_word(get)
+        return self.find_word(get, False)

+ 31 - 7
templates/test.html

@@ -5,9 +5,10 @@
         <p class="col-8 offset-2 text-center" > {{ about }} </p>
         <section class="mt-2 text-center">
             <ul id="test" class="nav nav-tabs justify-content-center mb-2">
-                <li class="active nav-item"> <a href="#question" data-toggle="tab" class="nav-link"> question </a> </li>
-                <li class="nav-item"> <a href="#info" data-toggle="tab" class="nav-link"> info </a> </li>
-                <li class="nav-item"> <a href="#answer" data-toggle="tab" class="nav-link"> answer </a> </li>
+                <li class="active nav-item"> <a href="#question" data-toggle="tab" class="nav-link"> Question </a> </li>
+                <li class="nav-item"> <a href="#info" data-toggle="tab" class="nav-link"> Info </a> </li>
+                <li class="nav-item"> <a href="#answer" data-toggle="tab" class="nav-link"> Answer </a> </li>
+                <li class="nav-item"> <a href="#user" data-toggle="tab" class="nav-link"> User </a> </li>
             </ul>
 
             <div id="testContent" class="tab-content">
@@ -53,14 +54,37 @@
                                 {% endfor %}
                             </ul>
                         {% endfor %}
-                        <div class="row justify-content-center">
-                            <a class="btn btn-info mr-2"> Right </a>
+                        <div class="row justify-content-center mb-2">
+
+                            <div id="DeleteModal" class="modal fade" role="dialog" aria-hidden="true">
+                                <div class="modal-dialog">
+                                    <div class="modal-content">
+                                        <div class="modal-header">
+                                            <h4 class="modal-title"> Do you sure delete this word? </h4>
+                                        </div>
+                                        <div class="modal-body">
+                                            <p> Do you sure delete '{{ word.name }}' ? </p>
+                                            <p> After doing this, you will never see this word again. </p>
+                                        </div>
+                                        <div class="modal-footer">
+                                            <a class="btn btn-danger" href="{{ url_for("test.delete", word=word.name) }}" > Sure </a>
+                                            <a class="btn btn-secondary" data-dismiss="modal"> No </a>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+
+                            <a class="btn btn-info mr-2" href="{{ url_for("test.right", word_id=word_id) }}"> Right </a>
                             <a class="btn btn-dark mr-2" href="{{ url_for("test.question") }}"> Next word </a>
-                            <a class="btn btn-danger mr-2"> Delete word </a>
-                            <a class="btn btn-info"> Wrong </a>
+                            <a class="btn btn-light mr-2" href="{{ url_for("test.download", word=word.name) }}"> Download word </a>
+                            <a class="btn btn-danger mr-2" data-toggle="modal" data-target="#DeleteModal" > Delete word </a>
+                            <a class="btn btn-info" href="{{ url_for("test.wrong", word_id=word_id) }}" > Wrong </a>
                         </div>
                     </div>
                 </div>
+                <div class="tab-pane fade" id="user">
+                    <p> There is user setting </p>
+                </div>
             </div>
         </section>