yunzi7 commited on
Commit
df42f36
β€’
1 Parent(s): 52c95a5

Feat: upload project

Browse files
Dockerfile ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as a parent image
2
+ FROM python:3.10-slim
3
+
4
+ # Set the working directory to /app
5
+ WORKDIR /app
6
+
7
+ # Copy the current directory contents into the container at /app
8
+ COPY . /app
9
+
10
+ # Install any needed packages specified in requirements.txt
11
+ RUN pip install --no-cache-dir -r requirements.txt
12
+
13
+ # Make port 7860 available to the world outside this container
14
+ EXPOSE 7860
15
+
16
+ # Run the Flask app directly using Python
17
+ CMD ["python", "app.py"]
README.md CHANGED
@@ -1,10 +1,78 @@
1
  ---
2
- title: Icebreaking
3
- emoji: ⚑
4
- colorFrom: red
5
- colorTo: gray
6
  sdk: docker
7
  pinned: false
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Ice Breaking Challenge
3
+ emoji: πŸ“š
4
+ colorFrom: purple
5
+ colorTo: yellow
6
  sdk: docker
7
  pinned: false
8
+ short_description: ice_breaking_challenge
9
  ---
10
 
11
+ # Ice Breaking Challenge
12
+ ## μ‚¬μš© μ‹œλ‚˜λ¦¬μ˜€
13
+ ```mermaid
14
+ sequenceDiagram
15
+ actor user as μ‚¬μš©μž
16
+ participant browser as λΈŒλΌμš°μ €
17
+ participant flask as Flask
18
+ %% participant sheets as Google Sheets
19
+ %% participant gemma as Fine-Tuned Gemma 2
20
+
21
+
22
+ autonumber
23
+ critical νŒ€ 정보 μž…λ ₯
24
+ user ->> browser: Hugging Face Space μ ‘κ·Ό
25
+ browser ->> flask: `νŒ€ 정보 μž…λ ₯ νŽ˜μ΄μ§€` μš”μ²­ (json)
26
+ flask ->> browser: `νŒ€ 정보 μž…λ ₯ νŽ˜μ΄μ§€` 응닡 (html & js)
27
+ browser ->> user: `νŒ€ 정보 μž…λ ₯ νŽ˜μ΄μ§€` λ Œλ”λ§
28
+ end
29
+
30
+ critical μ„€λ¬Έ QR
31
+ user ->> browser: `νŒ€ 정보 μž…λ ₯ νŽ˜μ΄μ§€`의 `λ‹€μŒ` λ²„νŠΌ 클릭
32
+ browser ->> flask: `μ„€λ¬Έ QR νŽ˜μ΄μ§€` μš”μ²­ (json)
33
+ flask ->> browser: `μ„€λ¬Έ QR νŽ˜μ΄μ§€` 응닡 (html & js)
34
+ browser ->> user: `μ„€λ¬Έ QR νŽ˜μ΄μ§€` λ Œλ”λ§
35
+ end
36
+
37
+ critical μžκΈ°μ†Œκ°œ
38
+ user ->> browser: `νŒ€ 정보 μž…λ ₯ νŽ˜μ΄μ§€`의 `λ‹€μŒ` λ²„νŠΌ 클릭
39
+ browser ->> flask: `μžκΈ°μ†Œκ°œ νŽ˜μ΄μ§€` μš”μ²­ (json)
40
+ flask ->> browser: `μžκΈ°μ†Œκ°œ νŽ˜μ΄μ§€` 응닡 (html & js)
41
+ browser ->> user: `μžκΈ°μ†Œκ°œ νŽ˜μ΄μ§€` λ Œλ”λ§
42
+ Note right of user: 질문 생성 μ™„λ£Œλ  λ•ŒκΉŒμ§€ `λ‹€μŒ` λ²„νŠΌ λ Œλ”λ§ X
43
+ end
44
+
45
+ critical μ„€λ¬Έ 및 질문 생성 μ™„λ£Œ 확인
46
+ browser ->> flask: μ„€λ¬Έ μ™„λ£Œ 확인 μš”μ²­ (json)
47
+ create participant sheets as Google Sheets
48
+ flask ->> sheets: μ„€λ¬Έ μš”μ²­
49
+ destroy sheets
50
+ sheets ->> flask: μ„€λ¬Έ 응닡
51
+ flask ->> flask: νŒ€ 정보와 μ„€λ¬Έ λ‚΄μ—­ λŒ€μ‘°
52
+ create participant gemma as Fine-Tuned Gemma 2
53
+ flask ->> gemma: μ„€λ¬Έ μ™„λ£Œλ˜μ—ˆλ‹€λ©΄, 질문 생성 μš”μ²­
54
+ destroy gemma
55
+ gemma ->> flask: 질문 생성 응닡
56
+ flask ->> browser: 질문 생성 μ™„λ£Œλœ 경우 `λ‹€μŒ` λ²„νŠΌ 응닡
57
+ browser ->> user: `λ‹€μŒ` λ²„νŠΌ λ Œλ”λ§
58
+ end
59
+
60
+ critical 젬마 생성 질문 1번
61
+ user ->> browser: `μžκΈ°μ†Œκ°œ νŽ˜μ΄μ§€`의 `λ‹€μŒ` λ²„νŠΌ 클릭
62
+ browser ->> flask: `생성 질문 1번 νŽ˜μ΄μ§€ μš”μ²­` (json)
63
+ flask ->> browser: `생성 질문 1번 νŽ˜μ΄μ§€ 응닡` (html & js)
64
+ browser ->> user: `생성 질문 1번 νŽ˜μ΄μ§€ 응닡` λ Œλ”λ§
65
+ end
66
+
67
+ critical 젬마 생성 질문 2번
68
+ user ->> browser: `생성 질문 1번 νŽ˜μ΄μ§€`의 `λ‹€μŒ` λ²„νŠΌ 클릭 (json)
69
+ Note left of flask: μ΄ν•˜ 동일
70
+ end
71
+
72
+ critical μΉœν•΄μ§€μ…¨λ‚˜μš”
73
+ user ->> browser: `생성 질문 λ§ˆμ§€λ§‰ νŽ˜μ΄μ§€`의 `λ‹€μŒ` λ²„νŠΌ 클릭 (json)
74
+ browser ->> flask: `생성 질문 λ§ˆμ§€λ§‰ νŽ˜μ΄μ§€` μš”μ²­ (json)
75
+ flask ->> browser: `생성 질문 λ§ˆμ§€λ§‰ νŽ˜μ΄μ§€` 응닡 (html & js)
76
+ browser ->> user: `생성 질문 λ§ˆμ§€λ§‰ νŽ˜μ΄μ§€` λ Œλ”λ§
77
+ end
78
+ ```
app.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from ice_breaking_challenge import create_app
2
+
3
+ if __name__ == "__main__":
4
+ app = create_app()
5
+ app.run(host="0.0.0.0", port=7860)
basic_test.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ def test_dummy():
2
+ pass
flask_session/2029240f6d1128be89ddc32729463129 ADDED
Binary file (9 Bytes). View file
 
flask_session/4b3a5c21ed5e4f46a96be9fe6a0bfb18 ADDED
Binary file (68 Bytes). View file
 
ice_breaking_challenge/__init__.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ from flask import Flask, session
4
+ from flask_session import Session
5
+
6
+
7
+ def create_app(test_config=None):
8
+ """Create and configure an instance of the Flask application."""
9
+ app = Flask(__name__, instance_relative_config=True)
10
+ app.config.from_mapping(
11
+ # a default secret that should be overridden by instance config
12
+ SECRET_KEY="dev",
13
+ # store the database in the instance folder
14
+ DATABASE=os.path.join(app.instance_path, "flaskr.sqlite"),
15
+ )
16
+ app.config['SESSION_TYPE'] = 'filesystem'
17
+ Session(app)
18
+
19
+ if test_config is None:
20
+ # load the instance config, if it exists, when not testing
21
+ app.config.from_pyfile("config.py", silent=True)
22
+ else:
23
+ # load the test config if passed in
24
+ app.config.update(test_config)
25
+
26
+ # ensure the instance folder exists
27
+ try:
28
+ os.makedirs(app.instance_path)
29
+ except OSError:
30
+ pass
31
+
32
+ @app.route("/hello")
33
+ def hello():
34
+ return "Hello, World!"
35
+
36
+ # register the database commands
37
+ # from . import db
38
+
39
+ # db.init_app(app)
40
+
41
+ # apply the blueprints to the app
42
+ # from . import auth
43
+ from . import index
44
+
45
+ # app.register_blueprint(auth.bp)
46
+ app.register_blueprint(index.bp)
47
+
48
+ # make url_for('index') == url_for('blog.index')
49
+ # in another app, you might define a separate main index here with
50
+ # app.route, while giving the blog blueprint a url_prefix, but for
51
+ # the tutorial the blog will be the main index
52
+ app.add_url_rule("/", endpoint="index")
53
+
54
+ return app
ice_breaking_challenge/auth.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import functools
2
+
3
+ from flask import Blueprint
4
+ from flask import flash
5
+ from flask import g
6
+ from flask import redirect
7
+ from flask import render_template
8
+ from flask import request
9
+ from flask import session
10
+ from flask import url_for
11
+ from werkzeug.security import check_password_hash
12
+ from werkzeug.security import generate_password_hash
13
+
14
+
15
+ bp = Blueprint("auth", __name__, url_prefix="/auth")
16
+
17
+
18
+ def login_required(view):
19
+ """View decorator that redirects anonymous users to the login page."""
20
+
21
+ @functools.wraps(view)
22
+ def wrapped_view(**kwargs):
23
+ if g.user is None:
24
+ return redirect(url_for("auth.login"))
25
+
26
+ return view(**kwargs)
27
+
28
+ return wrapped_view
29
+
30
+
31
+ @bp.before_app_request
32
+ def load_logged_in_user():
33
+ """If a user id is stored in the session, load the user object from
34
+ the database into ``g.user``."""
35
+ user_id = session.get("user_id")
36
+
37
+ if user_id is None:
38
+ g.user = None
39
+ else:
40
+ g.user = (
41
+ get_db().execute("SELECT * FROM user WHERE id = ?", (user_id,)).fetchone()
42
+ )
43
+
44
+
45
+ @bp.route("/register", methods=("GET", "POST"))
46
+ def register():
47
+ """Register a new user.
48
+
49
+ Validates that the username is not already taken. Hashes the
50
+ password for security.
51
+ """
52
+ if request.method == "POST":
53
+ username = request.form["username"]
54
+ password = request.form["password"]
55
+ db = get_db()
56
+ error = None
57
+
58
+ if not username:
59
+ error = "Username is required."
60
+ elif not password:
61
+ error = "Password is required."
62
+
63
+ if error is None:
64
+ try:
65
+ db.execute(
66
+ "INSERT INTO user (username, password) VALUES (?, ?)",
67
+ (username, generate_password_hash(password)),
68
+ )
69
+ db.commit()
70
+ except db.IntegrityError:
71
+ # The username was already taken, which caused the
72
+ # commit to fail. Show a validation error.
73
+ error = f"User {username} is already registered."
74
+ else:
75
+ # Success, go to the login page.
76
+ return redirect(url_for("auth.login"))
77
+
78
+ flash(error)
79
+
80
+ return render_template("auth/register.html")
81
+
82
+
83
+ @bp.route("/login", methods=("GET", "POST"))
84
+ def login():
85
+ """Log in a registered user by adding the user id to the session."""
86
+ if request.method == "POST":
87
+ team_number = request.form["team_number"]
88
+ team_size = request.form["team_size"]
89
+
90
+ if user is None:
91
+ error = "Incorrect username."
92
+ elif not check_password_hash(user["password"], password):
93
+ error = "Incorrect password."
94
+
95
+ if error is None:
96
+ # store the user id in a new session and return to the index
97
+ session.clear()
98
+ session["user_id"] = user["id"]
99
+ return redirect(url_for("index"))
100
+
101
+ flash(error)
102
+
103
+ return render_template("auth/login.html")
104
+
105
+
106
+ @bp.route("/logout")
107
+ def logout():
108
+ """Clear the current session, including the stored user id."""
109
+ session.clear()
110
+ return redirect(url_for("index"))
ice_breaking_challenge/blog.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Blueprint
2
+ from flask import flash
3
+ from flask import g
4
+ from flask import redirect
5
+ from flask import render_template
6
+ from flask import request
7
+ from flask import url_for
8
+ from werkzeug.exceptions import abort
9
+
10
+ from .auth import login_required
11
+ from .db import get_db
12
+
13
+ bp = Blueprint("blog", __name__)
14
+
15
+
16
+ @bp.route("/")
17
+ def index():
18
+ """Show all the posts, most recent first."""
19
+ db = get_db()
20
+ posts = db.execute(
21
+ "SELECT p.id, title, body, created, author_id, username"
22
+ " FROM post p JOIN user u ON p.author_id = u.id"
23
+ " ORDER BY created DESC"
24
+ ).fetchall()
25
+ return render_template("blog/index.html", posts=posts)
26
+
27
+
28
+ def get_post(id, check_author=True):
29
+ """Get a post and its author by id.
30
+
31
+ Checks that the id exists and optionally that the current user is
32
+ the author.
33
+
34
+ :param id: id of post to get
35
+ :param check_author: require the current user to be the author
36
+ :return: the post with author information
37
+ :raise 404: if a post with the given id doesn't exist
38
+ :raise 403: if the current user isn't the author
39
+ """
40
+ post = (
41
+ get_db()
42
+ .execute(
43
+ "SELECT p.id, title, body, created, author_id, username"
44
+ " FROM post p JOIN user u ON p.author_id = u.id"
45
+ " WHERE p.id = ?",
46
+ (id,),
47
+ )
48
+ .fetchone()
49
+ )
50
+
51
+ if post is None:
52
+ abort(404, f"Post id {id} doesn't exist.")
53
+
54
+ if check_author and post["author_id"] != g.user["id"]:
55
+ abort(403)
56
+
57
+ return post
58
+
59
+
60
+ @bp.route("/create", methods=("GET", "POST"))
61
+ @login_required
62
+ def create():
63
+ """Create a new post for the current user."""
64
+ if request.method == "POST":
65
+ title = request.form["title"]
66
+ body = request.form["body"]
67
+ error = None
68
+
69
+ if not title:
70
+ error = "Title is required."
71
+
72
+ if error is not None:
73
+ flash(error)
74
+ else:
75
+ db = get_db()
76
+ db.execute(
77
+ "INSERT INTO post (title, body, author_id) VALUES (?, ?, ?)",
78
+ (title, body, g.user["id"]),
79
+ )
80
+ db.commit()
81
+ return redirect(url_for("blog.index"))
82
+
83
+ return render_template("blog/create.html")
84
+
85
+
86
+ @bp.route("/<int:id>/update", methods=("GET", "POST"))
87
+ @login_required
88
+ def update(id):
89
+ """Update a post if the current user is the author."""
90
+ post = get_post(id)
91
+
92
+ if request.method == "POST":
93
+ title = request.form["title"]
94
+ body = request.form["body"]
95
+ error = None
96
+
97
+ if not title:
98
+ error = "Title is required."
99
+
100
+ if error is not None:
101
+ flash(error)
102
+ else:
103
+ db = get_db()
104
+ db.execute(
105
+ "UPDATE post SET title = ?, body = ? WHERE id = ?", (title, body, id)
106
+ )
107
+ db.commit()
108
+ return redirect(url_for("blog.index"))
109
+
110
+ return render_template("blog/update.html", post=post)
111
+
112
+
113
+ @bp.route("/<int:id>/delete", methods=("POST",))
114
+ @login_required
115
+ def delete(id):
116
+ """Delete a post.
117
+
118
+ Ensures that the post exists and that the logged in user is the
119
+ author of the post.
120
+ """
121
+ get_post(id)
122
+ db = get_db()
123
+ db.execute("DELETE FROM post WHERE id = ?", (id,))
124
+ db.commit()
125
+ return redirect(url_for("blog.index"))
ice_breaking_challenge/db.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sqlite3
2
+
3
+ import click
4
+ from flask import current_app
5
+ from flask import g
6
+
7
+
8
+ def get_db():
9
+ """Connect to the application's configured database. The connection
10
+ is unique for each request and will be reused if this is called
11
+ again.
12
+ """
13
+ if "db" not in g:
14
+ g.db = sqlite3.connect(
15
+ current_app.config["DATABASE"], detect_types=sqlite3.PARSE_DECLTYPES
16
+ )
17
+ g.db.row_factory = sqlite3.Row
18
+
19
+ return g.db
20
+
21
+
22
+ def close_db(e=None):
23
+ """If this request connected to the database, close the
24
+ connection.
25
+ """
26
+ db = g.pop("db", None)
27
+
28
+ if db is not None:
29
+ db.close()
30
+
31
+
32
+ def init_db():
33
+ """Clear existing data and create new tables."""
34
+ db = get_db()
35
+
36
+ with current_app.open_resource("schema.sql") as f:
37
+ db.executescript(f.read().decode("utf8"))
38
+
39
+
40
+ @click.command("init-db")
41
+ def init_db_command():
42
+ """Clear existing data and create new tables."""
43
+ init_db()
44
+ click.echo("Initialized the database.")
45
+
46
+
47
+ def init_app(app):
48
+ """Register database functions with the Flask app. This is called by
49
+ the application factory.
50
+ """
51
+ app.teardown_appcontext(close_db)
52
+ app.cli.add_command(init_db_command)
ice_breaking_challenge/index.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Blueprint
2
+ from flask import flash
3
+ from flask import g
4
+ from flask import redirect
5
+ from flask import render_template
6
+ from flask import request
7
+ from flask import url_for
8
+ from werkzeug.exceptions import abort
9
+ from flask import session
10
+
11
+ from .auth import login_required
12
+ from .db import get_db
13
+
14
+
15
+ bp = Blueprint("index", __name__)
16
+
17
+
18
+ @bp.route("/", methods=["GET", "POST"])
19
+ def index() -> None:
20
+ match request.method:
21
+ case "GET":
22
+ return render_template("index.html")
23
+ case "POST": # index.htmlμ—μ„œ `λ‹€μŒ` λ²„νŠΌ λˆŒλ €μ„ λ•Œ
24
+ session["team_number"] = request.form.get("team_number")
25
+ session["team_size"] = request.form.get("team_size")
26
+ return render_template("qr.html")
ice_breaking_challenge/introduction.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Blueprint
2
+ from flask import flash
3
+ from flask import g
4
+ from flask import redirect
5
+ from flask import render_template
6
+ from flask import request
7
+ from flask import url_for
8
+ from werkzeug.exceptions import abort
9
+ from flask import session
10
+
11
+ from .auth import login_required
12
+ from .db import get_db
13
+
14
+
15
+ bp = Blueprint("qr", __name__)
16
+
17
+
18
+ @bp.route("/", methods=["GET", "POST"])
19
+ def qr() -> None:
20
+ match request.method:
21
+ case "GET":
22
+ return render_template("qr.html")
23
+ case "POST": # qr.htmlμ—μ„œ `λ‹€μŒ` λ²„νŠΌ λˆŒλ €μ„ λ•Œ
24
+ return render_template("introduction.html")
ice_breaking_challenge/qr.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Blueprint
2
+ from flask import flash
3
+ from flask import g
4
+ from flask import redirect
5
+ from flask import render_template
6
+ from flask import request
7
+ from flask import url_for
8
+ from werkzeug.exceptions import abort
9
+ from flask import session
10
+
11
+ from .auth import login_required
12
+ from .db import get_db
13
+
14
+
15
+ bp = Blueprint("qr", __name__)
16
+
17
+
18
+ @bp.route("/", methods=["GET", "POST"])
19
+ def qr() -> None:
20
+ match request.method:
21
+ case "GET":
22
+ return render_template("qr.html")
23
+ case "POST": # qr.htmlμ—μ„œ `λ‹€μŒ` λ²„νŠΌ λˆŒλ €μ„ λ•Œ
24
+ return render_template("qr.html")
ice_breaking_challenge/schema.sql ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -- Initialize the database.
2
+ -- Drop any existing data and create empty tables.
3
+
4
+ DROP TABLE IF EXISTS user;
5
+ DROP TABLE IF EXISTS post;
6
+
7
+ CREATE TABLE user (
8
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
9
+ username TEXT UNIQUE NOT NULL,
10
+ password TEXT NOT NULL
11
+ );
12
+
13
+ CREATE TABLE post (
14
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
15
+ author_id INTEGER NOT NULL,
16
+ created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
17
+ title TEXT NOT NULL,
18
+ body TEXT NOT NULL,
19
+ FOREIGN KEY (author_id) REFERENCES user (id)
20
+ );
ice_breaking_challenge/static/style.css ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ html {
2
+ font-family: sans-serif;
3
+ background: #eee;
4
+ padding: 1rem;
5
+ }
6
+
7
+ body {
8
+ max-width: 960px;
9
+ margin: 0 auto;
10
+ background: white;
11
+ }
12
+
13
+ h1, h2, h3, h4, h5, h6 {
14
+ font-family: serif;
15
+ color: #377ba8;
16
+ margin: 1rem 0;
17
+ }
18
+
19
+ a {
20
+ color: #377ba8;
21
+ }
22
+
23
+ hr {
24
+ border: none;
25
+ border-top: 1px solid lightgray;
26
+ }
27
+
28
+ nav {
29
+ background: lightgray;
30
+ display: flex;
31
+ align-items: center;
32
+ padding: 0 0.5rem;
33
+ }
34
+
35
+ nav h1 {
36
+ flex: auto;
37
+ margin: 0;
38
+ }
39
+
40
+ nav h1 a {
41
+ text-decoration: none;
42
+ padding: 0.25rem 0.5rem;
43
+ }
44
+
45
+ nav ul {
46
+ display: flex;
47
+ list-style: none;
48
+ margin: 0;
49
+ padding: 0;
50
+ }
51
+
52
+ nav ul li a, nav ul li span, header .action {
53
+ display: block;
54
+ padding: 0.5rem;
55
+ }
56
+
57
+ .content {
58
+ padding: 0 1rem 1rem;
59
+ }
60
+
61
+ .content > header {
62
+ border-bottom: 1px solid lightgray;
63
+ display: flex;
64
+ align-items: flex-end;
65
+ }
66
+
67
+ .content > header h1 {
68
+ flex: auto;
69
+ margin: 1rem 0 0.25rem 0;
70
+ }
71
+
72
+ .flash {
73
+ margin: 1em 0;
74
+ padding: 1em;
75
+ background: #cae6f6;
76
+ border: 1px solid #377ba8;
77
+ }
78
+
79
+ .post > header {
80
+ display: flex;
81
+ align-items: flex-end;
82
+ font-size: 0.85em;
83
+ }
84
+
85
+ .post > header > div:first-of-type {
86
+ flex: auto;
87
+ }
88
+
89
+ .post > header h1 {
90
+ font-size: 1.5em;
91
+ margin-bottom: 0;
92
+ }
93
+
94
+ .post .about {
95
+ color: slategray;
96
+ font-style: italic;
97
+ }
98
+
99
+ .post .body {
100
+ white-space: pre-line;
101
+ }
102
+
103
+ .content:last-child {
104
+ margin-bottom: 0;
105
+ }
106
+
107
+ .content form {
108
+ margin: 1em 0;
109
+ display: flex;
110
+ flex-direction: column;
111
+ }
112
+
113
+ .content label {
114
+ font-weight: bold;
115
+ margin-bottom: 0.5em;
116
+ }
117
+
118
+ .content input, .content textarea {
119
+ margin-bottom: 1em;
120
+ }
121
+
122
+ .content textarea {
123
+ min-height: 12em;
124
+ resize: vertical;
125
+ }
126
+
127
+ input.danger {
128
+ color: #cc2f2e;
129
+ }
130
+
131
+ input[type=submit] {
132
+ align-self: start;
133
+ min-width: 10em;
134
+ }
ice_breaking_challenge/templates/auth/login.html ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+
3
+ {% block header %}
4
+ <h1>{% block title %}Log In{% endblock %}</h1>
5
+ {% endblock %}
6
+
7
+ {% block content %}
8
+ <form method="post">
9
+ <label for="username">Username</label>
10
+ <input name="username" id="username" required>
11
+ <label for="password">Password</label>
12
+ <input type="password" name="password" id="password" required>
13
+ <input type="submit" value="Log In">
14
+ </form>
15
+ {% endblock %}
ice_breaking_challenge/templates/auth/register.html ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+
3
+ {% block header %}
4
+ <h1>{% block title %}Register{% endblock %}</h1>
5
+ {% endblock %}
6
+
7
+ {% block content %}
8
+ <form method="post">
9
+ <label for="username">Username</label>
10
+ <input name="username" id="username" required>
11
+ <label for="password">Password</label>
12
+ <input type="password" name="password" id="password" required>
13
+ <input type="submit" value="Register">
14
+ </form>
15
+ {% endblock %}
ice_breaking_challenge/templates/base.html ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <title>{% block title %}{% endblock %} - Ice Breaking Challenge</title>
3
+ <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
4
+ <nav>
5
+ <h1><a href="{{ url_for('index') }}">Ice Breaking Challenge</a></h1>
6
+ </nav>
7
+ <section class="content">
8
+ <header>
9
+ {% block header %}{% endblock %}
10
+ </header>
11
+ {% for message in get_flashed_messages() %}
12
+ <div class="flash">{{ message }}</div>
13
+ {% endfor %}
14
+ {% block content %}{% endblock %}
15
+ </section>
ice_breaking_challenge/templates/blog/create.html ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+
3
+ {% block header %}
4
+ <h1>{% block title %}New Post{% endblock %}</h1>
5
+ {% endblock %}
6
+
7
+ {% block content %}
8
+ <form method="post">
9
+ <label for="title">Title</label>
10
+ <input name="title" id="title" value="{{ request.form['title'] }}" required>
11
+ <label for="body">Body</label>
12
+ <textarea name="body" id="body">{{ request.form['body'] }}</textarea>
13
+ <input type="submit" value="Save">
14
+ </form>
15
+ {% endblock %}
ice_breaking_challenge/templates/blog/index_.html ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+
3
+ {% block header %}
4
+ <h1>{% block title %}Posts{% endblock %}</h1>
5
+ {% if g.user %}
6
+ <a class="action" href="{{ url_for('blog.create') }}">New</a>
7
+ {% endif %}
8
+ {% endblock %}
9
+
10
+ {% block content %}
11
+ {% for post in posts %}
12
+ <article class="post">
13
+ <header>
14
+ <div>
15
+ <h1>{{ post['title'] }}</h1>
16
+ <div class="about">by {{ post['username'] }} on {{ post['created'].strftime('%Y-%m-%d') }}</div>
17
+ </div>
18
+ {% if g.user['id'] == post['author_id'] %}
19
+ <a class="action" href="{{ url_for('blog.update', id=post['id']) }}">Edit</a>
20
+ {% endif %}
21
+ </header>
22
+ <p class="body">{{ post['body'] }}</p>
23
+ </article>
24
+ {% if not loop.last %}
25
+ <hr>
26
+ {% endif %}
27
+ {% endfor %}
28
+ {% endblock %}
ice_breaking_challenge/templates/blog/update.html ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+
3
+ {% block header %}
4
+ <h1>{% block title %}Edit "{{ post['title'] }}"{% endblock %}</h1>
5
+ {% endblock %}
6
+
7
+ {% block content %}
8
+ <form method="post">
9
+ <label for="title">Title</label>
10
+ <input name="title" id="title" value="{{ request.form['title'] or post['title'] }}" required>
11
+ <label for="body">Body</label>
12
+ <textarea name="body" id="body">{{ request.form['body'] or post['body'] }}</textarea>
13
+ <input type="submit" value="Save">
14
+ </form>
15
+ <hr>
16
+ <form action="{{ url_for('blog.delete', id=post['id']) }}" method="post">
17
+ <input class="danger" type="submit" value="Delete" onclick="return confirm('Are you sure?');">
18
+ </form>
19
+ {% endblock %}
ice_breaking_challenge/templates/index.html ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+
3
+
4
+ {% block content %}
5
+ <form method="post">
6
+ <label for="team_number">νŒ€ 번호</label>
7
+ <input name="team_number" id="team_number" required>
8
+ <label for="team_size">νŒ€μ› 수</label>
9
+ <input name="team_size" id="team_size" required>
10
+ <input type="submit" value="λ‹€μŒ">
11
+ </form>
12
+ {% endblock %}
ice_breaking_challenge/templates/introduction.html ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+
3
+ {% block content %}
4
+ μžκΈ°μ†Œκ°œ ν•΄λ³΄μ„Έμš”
5
+ <form method="post">
6
+ <input type="submit" value="λ‹€μŒ">
7
+ </form>
8
+ {% endblock %}
ice_breaking_challenge/templates/qr.html ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'base.html' %}
2
+
3
+
4
+ {% block content %}
5
+ <button>qr</button>
6
+ <br>
7
+ λͺ¨λ“  νŒ€μ›λ“€μ΄ 섀문을 μ™„λ£Œν•˜λ©΄ μ•„λž˜ λ²„νŠΌμ„ λˆŒλŸ¬μ£Όμ„Έμš”.
8
+ <form method="post">
9
+ <input type="submit" value="λ‹€μŒ">
10
+ </form>
11
+ {% endblock %}
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ flask
2
+ Flask-Session
run.sh ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ source venv/bin/activate
2
+ python3 app.py
setup.sh ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ python3 -m venv venv
2
+ source venv/bin/activate
3
+ python3 -m pip install -r requirements.txt
4
+ pre-commit install