20.04.17 13:10 작성
·
176
1
로그인 보안 강화까지 강의를 들었습니다.
보안강화된 아이디로 로그인 한 후, 작성한 글 수정이 안됩니다.
아래와 같은 에러가 나타납니다.
board_edit
UnboundLocalError: local variable 'filename' referenced before assignment
adit.html
{% extends "main.html" %}{% block contents %}
<script>$(document).ready(function () {$("#summernote").summernote({heigth: 300,minHeight: null,maxHeight: null,lang: "ko-KR",popover: {image: [],link: [],air: []},//콜백함수는 호출이 되어진다.//이미지 업로드 관련callbacks: {onImageUpload: function(image) {for(var i = 0 ; i < image.length ; i++) {uploadImage(image[i]);}}}});});
//웹사이트 콘솔창에서 볼수 있는 것//function uploadImage(image) {// console.log(image);//}
function uploadImage(image) {//객체를 설정한다(담기 위한 그릇)var data = new FormData();console.log(image)// 넘어온 이미지 객체를 append 시켜준다.data.append("image", image);var csrf_token = "{{csrf_token()}}";
$.ajaxSetup({beforeSend: function(x, s){//s가 GET|HEAD|OPTIONS|TRACE 중 하나이면if(!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(s.type)){//x(내부통신을 전담하는 객체 에이젝스에서)가 해더를 추가하는데 해더의 이름은 X-CSRFToken이고 값은 csrf_token이다.x.setRequestHeader("X-CSRFToken", csrf_token)}}});$.ajax({//페이지 이동없이 내부적으로 통신한다.//url 주소로 찾아준다.url: "{{url_for('board.upload_image')}}",cache: false,contentType: false,processData: false,//데이터를data: data,//포스트 형식으로 전달한다.type:"post",//위 데이터 전송이 성공하면success: function(url) {//<omg src=서버주소> 태그를 생성해준다.var image = $("<img>").attr("src",url).css('max-width', "900px");//insertNode:이미지를 강제적으로 추가해준다.$("#summernote").summernote("insertNode",image[0]);},//성공하지 못하면 오류를 보여준다.error: function(data) {console.log(data);alert(data);}});}</script>
<script>function CheckEditForm() {if($.trim($("#title").val()) == "") {alert("제목을 입력하세요.");$("#title").focus();return false;}
if($.trim($("#summernote").val()) == "") {alert("내용을 입력하세요.");$("#summernote").focus();return false;}
return true;}</script>
<form name="form" method="POST" action="{{url_for('board.board_edit', idx=data._id)}}" enctype="multipart/form-data"><!--보안 강화--><input type="hidden" name="csrf_token" value="{{csrf_token()}}"><div class="form-group"><label for="name">작성자</label><input class="form-control" type="text" name="name" value="{{session['name']}}" readonly></div><div class="form-group"><label for="title">제목</label><input class="form-control" type="title" name="title" value={{data.title}} ></div>{% if data.attachfile %}<div class="form-check text-right"><input type="checkbox" class="form-check-input" id="deleteoldfile" name="deleteoldfile"><label class="form-check-label" for="deleteoldfile">첨부파일 삭제 ({{data.attachfile}})</label></div>{% endif %}<div class="form-group"><label for="contents">내용</label><textarea rows ="8" class="form-control" name="contents" id="summernote" >{{data.contents}}</textarea></div><!-- 파일 첨부 버튼 --><div class="custom-file"><input class="custom-file-input" id="customFile" type="file" name="attachfile"><label class="custom-file-label" for="customFile">파일선택</label></div><div class="text-center"><input class="btn btn-primary" type="submit" value="수정하기"></div></form>
<!--<table><form name="form" method="POST" action="{{url_for('board.board_edit', idx=data._id)}}"><tr><td>작성자</td><td><input type="text" name= "name" value="{{session['name']}}" readonly></td></tr><tr><td>제목</td><td><input type="text" name= "title" value={{data.title}}></td></tr><tr><td>내용</td><td><textarea name= "contents">{{data.contents}}</textarea></td></tr><tr><td colspan="2"><input type="submit"></td></tr></form></table> -->{% endblock %}#board.htmlfrom main import *# 큰 프로젝트시 /board/list 같은 것을 만들어주는 것from flask import Blueprint# 게시판에 관한 내용from flask import send_from_directory
#이 블루프린트의 이름은 "board"이고 블루프린트가 선언된 곳에 앞에다가는 모두 "/board"를 붙여준다.blueprint = Blueprint("board", __name__, url_prefix="/board")
# 첨부파일을 삭제하는 기능def board_delete_attach_file(filename):# abs : 절대경로abs_path = os.path.join(app.config["BOARD_ATTACH_FILE_PATH"], filename)# 파일이 abs에 존재하면if os.path.exists(abs_path):os.remove(abs_path)return Truereturn False
@blueprint.route("/upload_image", methods=["POST"])def upload_image():if request.method == "POST":file = request.files["image"]# 확장자가 문제 없다고 판단 되면if file and allowed_file(file.filename):# 임의의 랜덤의 문자 열로 파일명이 생성하게 된다.filename = "{}.jpg".format(rand_generator())# 실제 파일이 저장될 경로savefilepath = os.path.join(app.config["BOARD_IMAGE_PATH"], filename)# 파일저장file.save(savefilepath)# 주소를 리턴해준다.return url_for("board.board_images", filename=filename)
#@blueprint.route("/images/<filename>")def board_images(filename):# send_from_directory : 밖에 폴더에 접근하기 위한 함수# app.config["BOARD_IMAGE_PATH"] : 절대경로# filename : 그 파일의 이름# 독립적인 폴더에 저장하고 웹에서는 이와 같은 방식으로 접근한다.return send_from_directory(app.config["BOARD_IMAGE_PATH"], filename)
@blueprint.route("/files/<filename>")def board_files(filename):# as_attachment=True :다운로드 형태return send_from_directory(app.config["BOARD_ATTACH_FILE_PATH"], filename, as_attachment=True)
# 리스트@blueprint.route("/list")def lists():# 페이지 값(값이 없는 경우 기본 값은 1)page = request.args.get("page", default=1, type=int)# 한 페이지 당 몇 개의 게시물을 출력할 지limit = request.args.get("limit", 7, type=int)
search = request.args.get("search", -1, type=int)keyword = request.args.get("keyword", "", type=str)
# 최종적으로 완성된 쿼리를 만들 변수query = {}# 검색어 상태를 추가할 리스트 변수search_list = []
if search == 0:search_list.append({"title": {"$regex": keyword}})elif search == 1:search_list.append({"contents": {"$regex": keyword}})elif search == 2:search_list.append({"title": {"$regex": keyword}})search_list.append({"contents": {"$regex": keyword}})elif search == 3:search_list.append({"name": {"$regex": keyword}})# 검색 대상이 한 개라도 존재할 경우 query 변수에 $or 리스트를 쿼리 합니다.if len(search_list) > 0:query = {"$or": search_list}
print(query)
board = mongo.db.boarddatas = board.find(query).skip((page - 1) * limit).limit(limit).sort("pubdate",-1)# 전체 게시물의 총 개수tot_count = board.find(query).count()# 마지막 페이지의 수를 구합니다.last_page_num = math.ceil(tot_count / limit)# 페이지 블럭을 5개씩 표기block_size = 5# 현재 페이지 블럭의 위치block_num = int((page - 1)/block_size)# 블럭의 시작 위치block_start = int((block_size * block_num) + 1)# 블럭의 마지막 위치block_last = math.ceil(block_start + (block_size - 1))
return render_template("list.html",datas=datas,limit=limit,page=page,block_start=block_start,block_last=block_last,last_page_num=last_page_num,search=search,keyword=keyword,title="게시판 리스트" #main.html의 title 값이 된다.)
# 상세페이지@blueprint.route("/view/<idx>")@login_required# idx 값을 따라서 몽고 db에서 값을 가져오는 역할def board_view(idx):# post 노출되지 않고 GET은 노출 됨# idx = request.args.get("idx")if idx is not None:page = request.args.get("page")search = request.args.get("search")keyword = request.args.get("keyword")
board = mongo.db.board# data = board.find_one({"_id": ObjectId(idx)})data = board.find_one_and_update({"_id": ObjectId(idx)}, {"$inc": {"view": 1}}, return_document=True)
if data is not None:result = {"id": data.get("_id"),"name": data.get("name"),"title": data.get("title"),"contents": data.get("contents"),"pubdate": data.get("pubdate"),"view": data.get("view"),"writer_id": data.get("writer_id", ""),"attachfile": data.get("attachfile","")}
return render_template("view.html", result=result, page=page, search=search, keyword=keyword, title="글 상세보기")return abort(404)## 글쓰기@blueprint.route("/write", methods=["GET", "POST"])@login_requireddef board_write():# if session.get("id") is None:# return redirect(url_for("member_login"))if request.method == "POST":filename = None# 첨부된 파일이 있으면if "attachfile" in request.files:file = request.files["attachfile"]# 허용된 파일이라면if file and allowed_file(file.filename):# 파일 이름을 넘겨주고 새로운 파일 이름을 받는다.filename = check_filename(file.filename)# 새로운 파일 명으로 세이브해라file.save(os.path.join(app.config['BOARD_ATTACH_FILE_PATH'], filename))
name = request.form.get("name")title = request.form.get("title")contents = request.form.get("contents")
# print(name, title, contents)
current_utc_time = round(datetime.utcnow().timestamp() * 1000)board = mongo.db.board
post = {"name": name,"title": title,"contents": contents,"pubdate": current_utc_time,"writer_id": session.get("id"),"view": 0,
}# 위 post에 attachfile가 추가 되어 나온다.if filename is not None:post["attachfile"] = filename
x = board.insert_one(post)print(x.inserted_id)return redirect(url_for("board.board_view", idx=x.inserted_id))else:return render_template("write.html", title="글 작성")
@blueprint.route("/edit/<idx>", methods=["GET", "POST"])def board_edit(idx):if request.method == "GET":board = mongo.db.boarddata = board.find_one({"_id":ObjectId(idx)})if data is None:flash("해당 게시물이 존재하지 않습니다.")return redirect(url_for("board.lists"))else:if session.get("id") == data.get("writer_id"):return render_template("edit.html", data=data, title="글 수정")else:flash("글 수정 권한이 없습니다.")return redirect(url_for("board.lists"))else:title = request.form.get("title")contents = request.form.get("contents")# 값을 받는다.deleteoldfile = request.form.get("deleteoldfile", "")# db에 접속하여board = mongo.db.board# id 값을 가져와서data = board.find_one({"_id": ObjectId(idx)})# 둘의 값이 같으면if session.get("id") == data.get("writer_id"):file = None# 첨부파일이 추가된 상태라면if "attachfile" in request.files:file = request.files["attachfile"]# 파일이 있고 확장자(allowed_file(file.filename):)에도 문제가 없다면if file and allowed_file(file.filename):filename = check_filename(file.filename)#새로운 파일을 저장해라file.save(os.path.join(app.config["BOARD_ATTACH_FILE_PATH"], filename))
# 예전파일이 있는 경우에는 기존파일을 삭제하고 재업로드해라if data.get("attachfile"):board_delete_attach_file(data.get("attachfile"))# 첨부파일이 저장이 되진않았고else:# 체크박스에 체크를 한 경우 on이 들어온다.if deleteoldfile == "on":filename = Noneif data.get("attachfile"):board_delete_attach_file(data.get("attachfile"))# 새로운 첨부파일도 없고 기존의 첨부파일도 삭제하지 않는 경우else:filename = data.get("attachfile")
board.update_one({"_id": ObjectId(idx)}, {"$set": {"title": title,"contents": contents,"attachfile": filename}})flash("수정되었습니다.")return redirect(url_for("board.board_view", idx=idx))else:flash("글 수정 권한이 없습니다.")return redirect(url_for("board.lists"))
@blueprint.route("/delete/<idx>")def board_delete(idx):board = mongo.db.boarddata = board.find_one({"_id": ObjectId(idx)})if data.get("writer_id") == session.get("id"):board.delete_one({"_id": ObjectId(idx)})flash("삭제되었습니다.")else:flash("삭제 권한이 없습니다.")return redirect(url_for("board.lists"))
답변 1
1
2020. 04. 19. 00:28
보안강화된 아이디로 로그인 하게 되면 이전에 보안강화 되기전에 작성한 글은 문제가 있을 수 있습니다. 새로 아이디를 초기화 하고 다시 시도해보시기 바라며
# 파일이 있고 확장자(allowed_file(file.filename):)에도 문제가 없다면
if file and allowed_file(file.filename):
filename = check_filename(file.filename)
#새로운 파일을 저장해라
file.save(os.path.join(app.config["BOARD_ATTACH_FILE_PATH"], filename))
# 예전파일이 있는 경우에는 기존파일을 삭제하고 재업로드해라
if data.get("attachfile"):
board_delete_attach_file(data.get("attachfile"))
else:
filename = data.get("attachfile")
위에 올려주신 코드의 일부분에서 file 에 문제가 있는 경우의 예외를 위처럼 수정해보시기 바랍니다. else 문이 추가된 부분입니다.