DEV Community

Mate Technologies
Mate Technologies

Posted on

Build a Startup-Style File Sharing SaaS with Python (Flask) 🚀

In this tutorial we will build ShareFlow, a simple cloud file sharing platform using Python and Flask.

Users will be able to:

• Register and login
• Upload files
• Generate shareable download links
• Track download counts
• Delete files

By the end you’ll have a mini SaaS file sharing platform similar to Dropbox-style sharing systems.

Project source code:

👉 https://github.com/rogers-cyber/python-tiny-tools/tree/main/77-File-sharing-web-app

  1. Install Requirements

First install Flask.

pip install flask werkzeug
Enter fullscreen mode Exit fullscreen mode
  1. Project Structure

Create a simple project structure.

shareflow/
│
├── app.py
├── shareflow.db
└── storage/

The storage folder will hold uploaded files.

  1. Import Required Libraries

Create app.py and start by importing required modules.

import os
import uuid
import sqlite3
from datetime import datetime

from flask import (
    Flask, request, redirect, url_for,
    render_template_string, session,
    send_from_directory
)

from werkzeug.security import generate_password_hash, check_password_hash
from werkzeug.utils import secure_filename
Enter fullscreen mode Exit fullscreen mode

What these libraries do
Library Purpose
Flask Web framework
sqlite3 Database
uuid Unique file IDs
werkzeug.security Password hashing
secure_filename Safe file uploads

  1. Application Configuration

Now define application settings.

APP_NAME = "ShareFlow"
APP_VERSION = "1.0"

UPLOAD_FOLDER = "storage"
DATABASE = "shareflow.db"

os.makedirs(UPLOAD_FOLDER, exist_ok=True)
Enter fullscreen mode Exit fullscreen mode

This section defines:

• Upload directory
• Database file
• App metadata

os.makedirs() ensures the upload folder exists.

  1. Create the Flask App

Next initialize Flask.

app = Flask(__name__)
app.secret_key = "dev-secret"

app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER
Enter fullscreen mode Exit fullscreen mode

The secret key is required for sessions.

Sessions allow users to stay logged in.

  1. Database Helper Function

To simplify database access we create a helper.

def db():
    conn = sqlite3.connect(DATABASE)
    conn.row_factory = sqlite3.Row
    return conn
Enter fullscreen mode Exit fullscreen mode

row_factory allows accessing database rows like:

user["username"]

instead of index positions.

  1. Initialize the Database

Now we create the required tables.

def init_db():

    conn = db()

    conn.execute("""
    CREATE TABLE IF NOT EXISTS users(
        id INTEGER PRIMARY KEY,
        username TEXT UNIQUE,
        password TEXT
    )
    """)
Enter fullscreen mode Exit fullscreen mode

Users table

Stores account information.

Files table

Next create a table for uploaded files.

    conn.execute("""
    CREATE TABLE IF NOT EXISTS files(
        id TEXT PRIMARY KEY,
        user_id INTEGER,
        filename TEXT,
        path TEXT,
        size INTEGER,
        downloads INTEGER,
        created TEXT
    )
    """)

    conn.commit()
    conn.close()
Enter fullscreen mode Exit fullscreen mode

Each uploaded file tracks:

• owner
• size
• downloads
• upload date

  1. Detect Current Logged User

We create a helper to check who is logged in.

def current_user():

    if "user_id" not in session:
        return None

    conn = db()

    user = conn.execute(
        "SELECT * FROM users WHERE id=?",
        (session["user_id"],)
    ).fetchone()

    conn.close()

    return user
Enter fullscreen mode Exit fullscreen mode

This function is used to protect dashboard routes.

  1. User Registration

Now let's build the registration page.

@app.route("/register", methods=["GET","POST"])
def register():

    if request.method == "POST":

        username = request.form["username"]
        password = generate_password_hash(request.form["password"])
Enter fullscreen mode Exit fullscreen mode

We hash passwords for security.

Insert the new user:

        conn = db()

        conn.execute(
            "INSERT INTO users(username,password) VALUES(?,?)",
            (username,password)
        )

        conn.commit()
        conn.close()

        return redirect("/login")
Enter fullscreen mode Exit fullscreen mode

Simple registration form:

    return """
    <h2>Register</h2>
    <form method="post">
    <input name="username">
    <input name="password" type="password">
    <button>Register</button>
    </form>
    """
Enter fullscreen mode Exit fullscreen mode
  1. User Login

Next we create login functionality.

@app.route("/login", methods=["GET","POST"])
def login():

    if request.method == "POST":

        username = request.form["username"]
        password = request.form["password"]
Enter fullscreen mode Exit fullscreen mode

Find the user in the database.

        conn = db()

        user = conn.execute(
            "SELECT * FROM users WHERE username=?",
            (username,)
        ).fetchone()

        conn.close()
Enter fullscreen mode Exit fullscreen mode

Verify password and login.

        if user and check_password_hash(user["password"],password):

            session["user_id"] = user["id"]

            return redirect("/dashboard")
Enter fullscreen mode Exit fullscreen mode
Login form:

    return """
    <h2>Login</h2>
    <form method="post">
    <input name="username">
    <input name="password" type="password">
    <button>Login</button>
    </form>
    """
Enter fullscreen mode Exit fullscreen mode
  1. Dashboard Page

The dashboard shows uploaded files.

@app.route("/")
@app.route("/dashboard")
def dashboard():

    user = current_user()

    if not user:
        return redirect("/login")
Enter fullscreen mode Exit fullscreen mode

Only logged-in users can access it.

Load user files.

    conn = db()

    files = conn.execute(
        "SELECT * FROM files WHERE user_id=?",
        (user["id"],)
    ).fetchall()

    conn.close()
Enter fullscreen mode Exit fullscreen mode

Render the dashboard UI.

return render_template_string(DASHBOARD_HTML, files=files)
Enter fullscreen mode Exit fullscreen mode
  1. Upload Files

Next we allow users to upload files.

@app.route("/upload", methods=["POST"])
def upload():

    user = current_user()

    if not user:
        return redirect("/login")
Enter fullscreen mode Exit fullscreen mode

Save the uploaded file.

    file = request.files["file"]

    filename = secure_filename(file.filename)

    file_id = str(uuid.uuid4())[:10]

    path = os.path.join(
        UPLOAD_FOLDER,
        file_id + "_" + filename
    )

    file.save(path)
Enter fullscreen mode Exit fullscreen mode

Store file metadata.

    size = os.path.getsize(path)

    conn = db()

    conn.execute("""
    INSERT INTO files
    VALUES(?,?,?,?,?,?,?)
    """,(
        file_id,
        user["id"],
        filename,
        path,
        size,
        0,
        datetime.now()
    ))

    conn.commit()
    conn.close()
Enter fullscreen mode Exit fullscreen mode

Redirect back to dashboard.

  return redirect("/dashboard")
Enter fullscreen mode Exit fullscreen mode
  1. Download Files

Each file gets a shareable download link.

@app.route("/f/<file_id>")
def download(file_id):
Enter fullscreen mode Exit fullscreen mode

Find the file.

    conn = db()

    file = conn.execute(
        "SELECT * FROM files WHERE id=?",
        (file_id,)
    ).fetchone()

    conn.close()
Enter fullscreen mode Exit fullscreen mode

Increase download count.

    conn = db()

    conn.execute(
        "UPDATE files SET downloads = downloads + 1 WHERE id=?",
        (file_id,)
    )

    conn.commit()
    conn.close()
Enter fullscreen mode Exit fullscreen mode

Send the file to the user.

    directory = os.path.dirname(file["path"])
    filename = os.path.basename(file["path"])

    return send_from_directory(directory, filename, as_attachment=True)
Enter fullscreen mode Exit fullscreen mode
  1. Delete Files

Users can remove uploaded files.

@app.route("/delete/<file_id>")
def delete(file_id):
Enter fullscreen mode Exit fullscreen mode

Find the file.

    conn = db()

    file = conn.execute(
        "SELECT * FROM files WHERE id=?",
        (file_id,)
    ).fetchone()
Enter fullscreen mode Exit fullscreen mode

Delete the file from storage.

    if file:

        try:
            os.remove(file["path"])
        except:
            pass
Enter fullscreen mode Exit fullscreen mode

Remove it from the database.

        conn.execute(
            "DELETE FROM files WHERE id=?",
            (file_id,)
        )

        conn.commit()

    conn.close()

    return redirect("/dashboard")
Enter fullscreen mode Exit fullscreen mode
  1. Dashboard UI (TailwindCSS)

The dashboard UI uses TailwindCSS for styling.

<script src="https://cdn.tailwindcss.com"></script>
Enter fullscreen mode Exit fullscreen mode

Features:

• Upload form
• File table
• Download links
• Delete buttons
• Download statistics

  1. Run the Application

Start the server.

if __name__ == "__main__":

    init_db()

    print("ShareFlow starting...")
    print("http://127.0.0.1:5000")

    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

Run it with:

python app.py

Then open:

http://127.0.0.1:5000
Final Result 🎉

You now have a working file sharing SaaS with:

✔ User accounts
✔ Secure uploads
✔ Shareable links
✔ Download tracking
✔ File deletion

Top comments (0)