User:Youjung/SI30: Unbordering/Prototyping: Difference between revisions

From XPUB & Lens-Based wiki
 
Line 320: Line 320:
=== Cloning Git to Server ===
=== Cloning Git to Server ===
ssh to sergio and cd to public_html
ssh to sergio and cd to public_html
<pre>
git clone https://git.xpub.nl/youjung/Noticing_Dutch_Streets
cd Noticing_Dutch_Streets
</pre>
Then activate virtual environment and install requirement.txt
<pre>
uv venv
source .venv/bin/activate
uv pip install -r requirements.txt
</pre>

Latest revision as of 23:57, 31 May 2026

Documentation on prototyping with flask.

Flask Set up

Flask documentation page from prototyping class.

1. Install
$ uv venv
$ source .venv/bin/activate
$ uv pip install flask
2. Restarting your project
$ source .venv/bin/activate
$ flask --app <filename> run

PLACES I WOULD NORMALLY NOT VISIT IN ROTTERDAM

Idea

vernacular web design vibes...

Where are the places that you would normally not visit? And why would you not visit these places? Maybe it's because you do not have the needs, you do not like the vibe, you do not like the neighborhood or you have some kind of phobia.

Rotterdam is a culturally diverse city, and there are invisible borders that divide they neighborhood. What determines these borders can be boundaries created by cultural/religious differences. This boundary can be derived from fear, overwhelm, unfamiliarity or even disgust. You might need courage to cross these borders. These borders and boundaries are very situated on personal background. Through this flask prototype, I'd like to document places that I fear to visit, maybe with some friends and try to identify what are our borders. Maybe even find patterns and compare.

The protocol is that you have to physically visit the location, take a picture, maybe even go inside and engage with the people there and share an anecdote.

Requirements

This page needs a form that includes...

  • location name
  • address
  • visited check box
  • anecdote
  • image upload
  • select contributor

These collected data will be stored in a .json file and images would be collected in a separate folder.

File structure

CSS and uploaded images are stored in the static folder because they need to be directly accessible by the browser. Flask automatically serves anything in this folder publicly.

.
├── database.json
├── observations.py
├── static
│   ├── reset.css
│   ├── style.css
│   └── uploads
│       └── collectedimg.png
└── templates
    └── observations.html

Code

observations.py

1. Saving data to json

2. Uploading image

import json
import os
from flask import Flask, render_template, request
from prefix import PrefixMiddleware

app = Flask(__name__)

#UPLOAD TO SERVER
app.wsgi_app = PrefixMiddleware(app.wsgi_app, '/sergio/SI30/fieldwork-tools/places_i_would_not_visit')

os.makedirs("static/uploads", exist_ok=True)

@app.route("/", methods=["GET", "POST"])
def main():
    with open("database.json", "r") as f:
        observations = json.load(f)

    if request.method == "POST":
        observation = dict(request.form)

        img = request.files["images"]
        
        #ADD IMAGE
        if img and img.filename != "":
            img.save("static/uploads/" + img.filename)
            observation["image"] = img.filename
        else:
            observation["image"] = None

        observations.append(observation)

        #WRITE TO DATABASE
        with open("database.json", "w+") as f:
            f.write(json.dumps(observations, indent=2))

    return render_template("observations.html", observations=observations)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5110)
    # app.run(debug=True)

database.json

 []

If there is data, it would look like this:

at the last {}, you should not include ,

[
  {
    "name": "coffeeshop Bilbao",
    "address": "Carnisselaan 20A, 3083 HJ Rotterdam",
    "anecdote": "",
    "user": "Youjung",
    "image": "Screenshot 2026-04-14 at 14.50.45.png"
  },
  {
    "name": "andy's darts",
    "address": "Strevelsweg 734, 3083 AS Rotterdam",
    "anecdote": "",
    "user": "Youjung",
    "image": "Screenshot 2026-04-14 at 14.49.01.png"
  }
]

observations.html

Use if statement {% if observation.visitor %} {% elif %} {% endif %}

<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='reset.css') }}">

<!-- TITLE & DESCRIPTION -->
<div class="about">
    <h1>PLACES I WOULD NORMALLY<br>NOT VISIT IN ROTTERDAM</h1>
    <p>What are the invisible boundaries or borders within the city in Rotterdam? These borders are very personal and different according where the person is from. I've gathered places that I would not go or I need big courage to go. Maybe I should visit them. I wonder what their reaction would be. </p>

<!-- FORM -->
 <details>
    <summary>Location Upload Form</summary>
    <form method="POST" enctype="multipart/form-data">
        <label for="name">Location Name</label>
        <textarea name="name"></textarea>
        <label for="address">Address</label>
        <textarea name="address"></textarea>
        <label for="anecdote">Anecdote on why you are hesitant to enter</label>
        <textarea name="anecdote"></textarea>

        <label for="visited">Visited</label>
        <input type="checkbox" name="visited" id="">
        
        <label name="images">Upload Image</label>
        <input type="file" id="images" name="images" accept="image/png, image/jpeg, image/jpg">

        <label name="user-select">By whom</label>
        <select name="user" id="user">
            <option value="">I am...</option>
            <option value="Youjung">Youjung</option>
            <option value="Daan">Daan</option>
        </select>
        
        <input id="collect" type="submit" value="COLLECT"/>
    </form>
</details>
<details>
    <summary>Collector Profile</summary>
        <div class="collector-box">
            <div class="collector">
                <p class="name">Youjung</p>
                <p>
                    Nationality: South Korean<br>
                    Age: 27<br>
                    Pronouns: she/her<br>
                    Religion: atheist<br>
                    Occupation: Master student at Piet Zwart Institute<br>
                    About:
                </p>
            </div>
            <div class="collector">
                <p class="name">Daan</p>
                <p>
                    Nationality: Dutch<br>
                    Age: <br>
                    Pronouns: <br>
                    Religion: <br>
                    Occupation: <br>
                    About: 
                </p>
            </div>
        </div>
    
</details>
</div>
<!-- OUTPUT GRID -->
<div class="grid">
{% for observation in observations %}
    #CUSTOMIZED BORDER FOR EACH USER
    <div class="box" style="border: 1px dashed {% if observation.user == 'Youjung' %}deeppink{% elif observation.user == 'Daan' %}lime{% else %}white{% endif %}">
        <div>
            <span class="attr">Name: </span>
            <span>{{ observation.name }}</span>
        </div>
        <div>
            <span class="attr">Address: </span>
            <span>{{ observation.address }}</span>
        </div>
        <div>
            {% if observation.visited %}
            <span class="attr">Visited: </span>
            <span>Yes</span>
            {% else %}
            <span class="attr">Visited: </span>
            <span>No</span>
            {% endif %}
        </div>
        <div>
            <span class="attr">Collector: </span>
            <span>{{ observation.user }}</span>
        </div>
        <div>
            <span class="attr">Anecdote: </span>
            <span>{{ observation.anecdote }}</span>
        </div>
        <div>
            {% if observation.image %}
            <img src="{{ url_for('static', filename='uploads/' + observation.image) }}" style="width: 100%; margin-top: 0.5rem;">
            {% endif %}
        </div>
    </div>
{% endfor %}
</div>

Uploading to Sergio(server)

Followed this documentation but encountered some problems. This is how I solved it.

1. Replace .venv and install flask

# remove existing venv
rm -rf .venv

# make new venv on server
python3 -m venv .venv

# install flask
.venv/bin/pip install flask

2. Import PrefixMiddleware in observation.py

from prefix import PrefixMiddleware

3. Host setting --host=0.0.0.0 0.0.0.0 means listen to all network not only localhost.

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5110)
    # app.run(debug=True)

4. Reload nginx

 sudo nginx -t
 sudo systemctl reload nginx

5. 413 Request Entity too large nginx image size is limited to 1MB. So open nginx

 sudo nano /etc/nginx/sites-enabled/hub.xpub.nl

Edit maximum file size

 location /sergio/SI30/fieldwork-tools/places_i_would_not_visit/ {
         client_max_body_size 5M;
         proxy_pass http://localhost:5110/sergio/SI30/fieldwork-tools/places_i_would_not_visit/;
         include proxy_params;
 }

Editing the file and updating

  • systemmd system file name: placesiwouldnotvisit.service
$ sudo systemctl start placesiwouldnotvisit
$ sudo systemctl status placesiwouldnotvisit
$ sudo systemctl restart placesiwouldnotvisit
$ sudo systemctl stop placesiwouldnotvisit
$ sudo systemctl enable placesiwouldnotvisit

Noticing Dutch Streets

git repository

Uploading file to git

1. Create Repository

2. Follow the step below to upload files

If you are working with flask add .gitignore. It ignores the .venv and image folders.

git init
touch README.md
touch .gitignore

In .gitignore write this

venv/
__pycache__/
*.pyc
.env
static/uploads/

And then Push!

git add .
git commit -m "add message"
git push

The command below allows you to save packages that were installed using pip in the virtual environment.

uv pip freeze > requirements.txt
git commit -m "add message"
git push

Cloning Git to Server

ssh to sergio and cd to public_html

git clone https://git.xpub.nl/youjung/Noticing_Dutch_Streets
cd Noticing_Dutch_Streets

Then activate virtual environment and install requirement.txt

uv venv
source .venv/bin/activate
uv pip install -r requirements.txt