Bladeren bron

feat: 下载文件

SongZihuan 2 jaren geleden
bovenliggende
commit
167c873422
3 gewijzigde bestanden met toevoegingen van 91 en 15 verwijderingen
  1. 43 0
      mailbox/email.py
  2. 27 11
      templates/mailbox/mail.html
  3. 21 4
      web/mailbox.py

+ 43 - 0
mailbox/email.py

@@ -18,6 +18,22 @@ class PLAIN:
         self.type = "text/plain"
 
 
+class FILE:
+    def __init__(self, filename, byte: bytes, content_type: str, content_disposition: str):
+        self.filename = filename
+        self.size = len(byte) / 1024 / 1024  # 换算得到mb
+        self.content_type = content_type
+        self.content_disposition = content_disposition
+
+        if self.size >= 0.1:
+            self.size_str = f"{self.size:.2f}MB"
+        elif self.size * 1024 > 0.1:
+            self.size_str = f"{self.size * 1024:.2f}KB"
+        else:
+            self.size_str = f"{int(self.size * 1024 * 1024):d}B"
+
+
+
 class Mail:
     date_pattern = re.compile(
         r"[A-Za-z]+, "
@@ -140,6 +156,33 @@ class Mail:
                 with open(filepath, 'wb') as f:
                     f.write(part.get_payload(decode=True))
 
+    @property
+    def file_list(self):
+        res = []
+        for part in self.msg_data.walk():
+            if part.get_content_maintype() == 'multipart':
+                continue
+            if part.get('Content-Disposition') is None:
+                continue
+
+            filename = part.get_filename()
+            if filename:
+                print(part.get_payload(decode=True))
+                res.append(FILE(filename, part.get_payload(decode=True),
+                                part.get_content_type(), part.get('Content-Disposition')))
+        return res
+
+    def get_file(self, filename) -> "(bytes, str, str) | (None, None, None)":
+        for part in self.msg_data.walk():
+            if part.get_content_maintype() == 'multipart':
+                continue
+            if part.get('Content-Disposition') is None:
+                continue
+
+            if filename == part.get_filename():
+                return part.get_payload(decode=True), part.get_content_type(), part.get('Content-Disposition')
+        return None, None, None
+
     def __lt__(self, other: "Mail"):
         return self.date < other.date
 

+ 27 - 11
templates/mailbox/mail.html

@@ -10,22 +10,38 @@
     </div>
 
     {% for i in html_id %}
-        <div class="alert alert-success mt-3">
-            <strong>Wow!</strong> 这里有一封HTML邮件。</a>。
+        <div class="card my-2">
+            <div class="card-header"> HTML邮件格式 </div>
+            <iframe class="col-12 my-2 viewer"
+                    src="{{ url_for("mailbox.html_page", date=date, select=select, mail=mail_id, id=i) }}">
+                你的浏览器不支持查阅此邮件。
+            </iframe>
         </div>
-        <iframe class="col-12 my-2 viewer"
-                src="{{ url_for("mailbox.html_page", date=date, select=select, mail=mail_id, id=i) }}">
-            你的浏览器不支持查阅此邮件。
-        </iframe>
     {% endfor %}
 
     {% for i in plain %}
-        <div class="alert alert-info mt-3">
-            <strong>Hi!</strong> 这是一封普通邮件。</a>。
+        <div class="card my-2">
+            <div class="card-header"> 普通邮件格式 </div>
+            <div class="card-body">
+                {{ i.body }}
+            </div>
+        </div>
+    {% endfor %}
+
+    {% for i in file_list %}
+        <div class="card my-2">
+            <div class="card-header"> {{ i.filename }} </div>
+            <div class="card-body">
+                <div class="text-start">
+                    大小:{{ i.size_str }}
+                    <br>
+                    类型:{{ i.content_type }}
+                </div>
+                <div class="text-end">
+                    <a class="card-link" href="{{ url_for("mailbox.file_page", date=date, select=select, mail=mail_id, filename=i.filename) }}"> 下载 </a>
+                </div>
+            </div>
         </div>
-        <p style="text-indent: 2rem;word-break:break-all;">
-            {{ i.body }}
-        </p>
     {% endfor %}
 
 </div>

+ 21 - 4
web/mailbox.py

@@ -1,4 +1,4 @@
-from flask import Blueprint, render_template, request, flash, abort
+from flask import Blueprint, render_template, request, flash, abort, make_response
 from flask_login import login_required, current_user
 from flask_wtf import FlaskForm
 from wtforms import DateField, SelectField, SubmitField
@@ -70,7 +70,6 @@ def mail_list_page():
             mail_list = []
         elif download:
             flash("启动新任务下载邮件,请稍后")
-            mail_list = []
 
         next_date = strftime("%Y-%m-%d", localtime(mktime(date_obj) + 24 * 60 * 60))
         last_date = strftime("%Y-%m-%d", localtime(mktime(date_obj) - 24 * 60 * 60))
@@ -118,6 +117,23 @@ def html_page():
     return abort(404)
 
 
+@mailbox.route("/file")
+@login_required
+def file_page():
+    filename = request.args.get("filename", None, type=str)
+    if not filename:
+        abort(404)
+    mail, *_ = __get_mail()
+    byte, content_type, content_disposition = mail.get_file(filename)
+    if not byte:
+        abort(404)
+
+    response = make_response(byte)
+    response.headers['Content-Type'] = content_type
+    response.headers['Content-Disposition'] = content_disposition
+    return response
+
+
 @mailbox.route("/mail")
 @login_required
 def mail_page():
@@ -132,11 +148,12 @@ def mail_page():
             html_id.append(count)
         elif type(i) is PLAIN:
             plain.append(i)
-
+    file_list = mail.file_list
     return render_template("mailbox/mail.html",
                            date=date,
                            select=select,
                            mail_id=mail_id,
                            mail=mail,
                            html_id=html_id,
-                           plain=plain)
+                           plain=plain,
+                           file_list=file_list)