のこりの処理
mainの全体像
main.py
from flask import Flask, redirect, jsonify, url_for, render_template, request, session from flask_bcrypt import Bcrypt import datetime import user import event import driveFile import photoBase import paticip import os import json app = Flask(__name__) bcrypt = Bcrypt(app) app.secret_key = 'ameamefurefure' app.permanent_session_lifetime = datetime.timedelta(minutes=3) @app.route("/login", methods = ["POST", "GET"]) def login(): if request.method == "POST": session.permanent = True userid = request.form.get("id") password = request.form.get("password") passByte = bcrypt.generate_password_hash(password=password) passHash = passByte.decode('utf-8') if request.form.get("signin"): # 存在チェック users = user.User() checkid = users.getUser({"id":userid}) if checkid.count > 0 and userid == checkid.items[0].get("id"): if bcrypt.check_password_hash(checkid.items[0].get("password"),password): session["id"] = userid return redirect(url_for("top")) else: return render_template("login.html",errmess="idまたはpasswordが違います") else: return render_template("login.html",errmess="idまたはpasswordが違います") elif request.form.get("signup"): # 存在チェック users = user.User() checkid = users.getUser({"id":userid}) if checkid != "" and passHash != "": if userid in [i['id'] for i in checkid.items]: return render_template("login.html",errmess="idがすでに使われています") else: users.newUser(userid,passHash) session["id"] = userid return render_template("signup.html",id=userid) else: return render_template("login.html",errmess="idを指定してください") # login済みであれば入場できる else: if "id" in session: return redirect(url_for("top")) return render_template("login.html") @app.route("/", methods=["GET","POST"]) def top(): """ login済であればイベント一覧やメッセージを見ることができる """ if "id" in session: events = event.Event() t = datetime.date.today() edata = events.dirCurrentEvents(t.strftime("%Y-%m-%d")) errmess = "" if edata.count <= 10 else "イベントが満杯です" patic = paticip.Paticip() rSQL = [] for e in edata.items: if e["id"] == session["id"]: eSQL = {} eSQL["eventid"] = e["key"] rSQL.append(eSQL) if rSQL: rdata = patic.getRequest(rSQL) else: rdata = None return render_template("index.html", id=session["id"],edata=edata,rdata=rdata,errmess=errmess) return render_template("login.html") @app.route("/signup", methods=["GET"]) def help(): return render_template("signup.html",id=session["id"]) @app.route("/newevent", methods = ["POST"]) def saveEvent(): # 新規または編集の保存 eventname = request.form.get("eventname") email = request.form.get("email") limitdate = request.form.get("limitdate") comment = request.form.get("comment") events = event.Event() limitStr = events.fmtDate(limitdate,"-") if request.form.get("make"): if request.form.get("ekey"): key = request.form.get("ekey") edataorg = events.getEvent(key) patic = edataorg.items[0].paticip events.updateEvent(key, session["id"], eventname, limitStr, comment, email, patic) return redirect(url_for("top")) # 新規登録 else: t = datetime.date.today() patic = [session["id"]] events.newEvent(session["id"], eventname, t.strftime("%Y-%m-%d"), limitStr, comment, email, patic) return redirect(url_for("top")) else: return redirect(url_for("top")) @app.route("/event/<ekey>", methods = ["GET"]) def editEvent(ekey): # 編集の入り if "id" in session: # 編集の読み込み if ekey: events = event.Event() edata = events.getEvent({"key":ekey}) return render_template("event.html", id=session["id"],edata=edata) else: return render_template("login.html") @app.route("/event", methods = ["GET"]) def newEvent(): # 新規の入り if "id" in session: t = datetime.date.today() firstDay = t.strftime("%Y-%m-%d") defaultLimit = t + datetime.timedelta(days=10) return render_template("event.html", id=session["id"],firstDay=firstDay,limit=defaultLimit) else: return render_template("login.html") @app.route("/newphoto/<ekey>/<string:photoFlag>", methods = ["GET"]) def newPhoto(ekey,photoFlag): # 新規の入り if "id" in session: if ekey: events = event.Event() edata = events.getEvent({"key":ekey}) return render_template("photoadd.html", id=session["id"],ekey=ekey,edata=edata,photoFlag=photoFlag) else: return render_template("login.html") else: return render_template("login.html") @app.route("/savephoto", methods = ["POST"]) def savePhoto(): # 写真の保存 if "id" in session: if request.form.get("regist"): comments = request.form.get("comments") photoFlag = request.form.get("photoFlag") filedata = request.files['file'] f = filedata.filename #実ファイル名 drive = driveFile.DriveFile() tmpfilename = drive.randStr(10) #temporaryファイル名 request.files['file'].save('/tmp/' + tmpfilename) #一旦/tmp別名で保存する # length = os.stat('/tmp/'+ tmpfilename).st_size #ファイルサイズを調べる tmpfile = open('/tmp/'+tmpfilename,'rb') #imageファイルの中身を読み込む tmpdata = tmpfile.read() res = drive.putFile( f,tmpdata ) #Driveに保存する tmpfile.close() #imageファイルを閉じる exif = drive.get_exif_of_image('/tmp/'+tmpfilename) #exifで撮影日付を取得する os.remove('/tmp/'+tmpfilename) #imageファイルを消す ekey = request.form.get("ekey") photo = photoBase.PhotoBase() photo.newPhoto(session["id"], ekey, f, False, exif['DateTime'],0,comments) return redirect(url_for("dirPhotos",ekey=ekey,photoFlag=photoFlag)) else: return redirect(url_for("top")) else: return render_template("login.html") @app.route("/photos/<ekey>/<string:photoFlag>", methods = ["GET"]) def dirPhotos(ekey,photoFlag): # イベント一覧の入り if "id" in session: if ekey: events = event.Event() edata = events.getEvent({"key":ekey}) pdata = events.dirEventPhotos(ekey,photoFlag) errmess = "" if pdata == None or len(pdata) <= 10 else "写真が満杯です" return render_template("photos.html", id=session["id"],edata=edata,pdata=pdata,photoFlag=photoFlag,errmess=errmess) else: return render_template("login.html") @app.route("/photo/<ekey>/<pkey>/<filename>", methods = ["GET"]) def deletePhoto(ekey,pkey,filename): # イベント一覧の入り if "id" in session: if pkey: drives = driveFile.DriveFile() photos = photoBase.PhotoBase() events = event.Event() drives.deleteFile(filename) photos.deletePhoto(pkey) edata = events.getEvent({"key":ekey}) pdata = events.dirEventPhotos(ekey,False) return render_template("photos.html", id=session["id"],edata=edata,pdata=pdata,photoFlag=False) else: return render_template("login.html") @app.route("/request/<ekey>/<id>", methods = ["GET"]) def sendRequest(ekey,id): # 参加の入り if "id" in session: events = event.Event() edata = events.getEvent({"key":ekey}) return render_template("request.html", id=session["id"],edata=edata) else: return render_template("login.html") @app.route("/request", methods = ["POST"]) def postRequest(): # 参加の保存 if "id" in session: fromid = request.form.get("fromid") ekey = request.form.get("key") eventname = request.form.get("event") rmemo = request.form.get("rmemo") events = event.Event() if request.form.get("request"): #申請 patic = paticip.Paticip() result = patic.getRequest({"userid":fromid,"eventid":ekey}) if result.count > 0: edata = events.getEvent({"key":ekey}) errmess = "申請済みです" return render_template("request.html", id=session["id"],edata=edata,errmess=errmess) else: patic.newRequest(ekey,eventname,fromid,rmemo) return redirect(url_for("top")) else: return render_template("login.html") @app.route("/patic/<pkey>/<fromid>", methods = ["GET"]) def sendPatic(pkey,fromid): # 許可の入り if "id" in session: patic = paticip.Paticip() pdata = patic.getRequest({"key":pkey}) return render_template("patic.html", id=session["id"],pdata=pdata) else: return render_template("login.html") @app.route("/patic", methods = ["POST"]) def postPatic(): # 許可の保存 if "id" in session: fromid = request.form.get("fromid") pkey = request.form.get("pkey") ekey = request.form.get("ekey") patic = paticip.Paticip() if request.form.get("accept"): #許可 events = event.Event() edataorg = events.getEvent({"key":ekey}) paticList = edataorg.items[0]["paticip"] #許可追加 if not fromid in paticList: paticList.append(fromid) events.updateEvent(ekey, session["id"], edataorg.items[0]["eventname"], edataorg.items[0]["firstDay"], edataorg.items[0]["limitdate"], edataorg.items[0]["comment"], edataorg.items[0]["email"], paticList) patic.deleteRequest(pkey) elif request.form.get("ban"): patic.deleteRequest(pkey) return redirect(url_for("top")) else: return render_template("login.html") @app.route("/logout", methods=["GET"]) def logout(): #期限切れ写真の削除 events = event.Event() photos = photoBase.PhotoBase() drive = driveFile.DriveFile() t = datetime.date.today() edata = events.dirLostEvents(t.strftime("%Y-%m-%d")) for e in edata.items: pdata = events.dirEventPhotos(e["key"],True) if pdata != None: for p in pdata: drive.deleteFile(p["filename"]) photos.deletePhoto(p["key"]) events.deleteEvent(e["key"]) session.pop('id',None) session.clear() return redirect("/") if __name__ == '__main__': app.debug = True app.run(host='localhost',threaded=True)
ばらばらに掲載したので最後にまとめました
css部分
/static/css/style.css
html, body { height: 100%; } body { padding-bottom: 40px; background-color: #f5f5f5; } /* * Singin */ #login-form { display: flex; align-items: center; } .form-signin { width: 100%; max-width: 330px; padding: 15px; margin: auto; } .form-signin .checkbox { font-weight: 400; } .form-signin .form-floating:focus-within { z-index: 2; } .form-signin input[type="text"] { margin-bottom: -1px; border-bottom-right-radius: 0; border-bottom-left-radius: 0; } .form-signin input[type="password"] { margin-bottom: 10px; border-top-left-radius: 0; border-top-right-radius: 0; } /* * index */ #index-header { display: inline-flex; } .navbar { margin-bottom: 20px; } .event-dir { background-color: #f1f4f4; } .message-dir { background-color: #f1f4f4; } .list-bgcolor { background-color: rgb(134, 157, 199); }
特に同じにする必要はありません
環境設定ファイル
requirements.txt
flask deta Pillow flask_bcrypt
この処理で必要なライブラリーです。flask_bcryptがパスワードの暗号化の部分です
Spacefile
# Spacefile Docs: https://go.deta.dev/docs/spacefile/v0 v: 0 micros: - name: eventphotos src: ./ engine: python3.9 primary: true
deta.spaceで追加された設定ファイルです
全体のまとめ
まあなんとかできましたが、実用的ではありません。せめて10秒のタイムアウトがなければいいのですが
WEB APIとしてデータを返すパターンが向いていると思います。
とりあえず、私が作ったサンプルを公開しますeventphotos
ユーザーは一度作ると消せないので、パスワード等しっかり管理してください。ただし、いつまで公開するか保証のかぎりではありません。