eventphotosのまとめ

まとめ

のこりの処理

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

ユーザーは一度作ると消せないので、パスワード等しっかり管理してください。ただし、いつまで公開するか保証のかぎりではありません。