diff --git a/README.md b/README.md new file mode 100644 index 0000000..e73aa0f --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# Google Suite Hub (demo) + +Repo zawiera działającą, lokalną wersję demo 4‑w‑1: Gmail, Google Tasks, Google Calendar oraz Habits. Obecnie dane są przykładowe (mock), ale architektura i UI są gotowe do podpięcia prawdziwych usług Google przez OAuth. + +## Co już działa +- **Dashboard webowy** (Flask + Jinja) z kartami: Gmail, Tasks, Calendar, Habits. +- **Przykładowe dane** po stronie backendu, żeby zobaczyć wygląd i układ aplikacji od razu po uruchomieniu. + +## Jak uruchomić lokalne demo +1. Upewnij się, że masz Python 3.11+. +2. Zainstaluj zależności: + ```bash + pip install -r requirements.txt + ``` +3. Uruchom serwer developerski: + ```bash + flask --app app run + ``` +4. Wejdź w przeglądarce na `http://localhost:5000` – zobaczysz połączony widok Gmail/Tasks/Calendar/Habits z mock danymi. + +> **Tip:** Kod szablonu jest w `templates/index.html`, a dane generuje `app.py` w funkcjach `mock_*`. + +## Architecture sketch +- **Frontend**: Web UI (SPA or server-rendered) that hits a backend API after OAuth completes. +- **Backend**: Handles OAuth code exchange, stores tokens securely, and calls Google APIs. +- **Data storage**: A small database (e.g., SQLite/PostgreSQL) to persist user profiles, refresh tokens, and habit logs. +- **Google APIs**: Gmail API, Google Tasks API, Google Calendar API via REST (e.g., google-api-python-client). + +## OAuth setup (required) +1. Create a Google Cloud project. +2. Enable Gmail API, Google Tasks API, and Google Calendar API. +3. Configure OAuth consent screen and authorized redirect URIs. +4. Create OAuth 2.0 Client ID (Web application) and note the **Client ID** and **Client secret**. +5. Set environment variables for local development (example): + ```bash + export GOOGLE_CLIENT_ID="your-client-id" + export GOOGLE_CLIENT_SECRET="your-client-secret" + export OAUTH_REDIRECT_URI="http://localhost:8000/oauth/callback" + ``` + +## Minimal flow (backend) +1. Redirect the user to Google's OAuth URL with scopes: + - `https://www.googleapis.com/auth/gmail.readonly` + - `https://www.googleapis.com/auth/tasks.readonly` + - `https://www.googleapis.com/auth/calendar.readonly` +2. Exchange the authorization code for access + refresh tokens. +3. Persist tokens securely (per user) along with token expiry. +4. Use access tokens to call the respective APIs: + - Gmail: `users.messages.list` for recent messages. + - Tasks: `tasks.list` for the default list. + - Calendar: `events.list` for upcoming events. +5. Render aggregated data to the UI alongside locally stored habits. + +## Habits data model (local) +- `habit` table: `id`, `user_id`, `name`, `cadence` (e.g., daily/weekly), `created_at`. +- `habit_checkin` table: `id`, `habit_id`, `date`, `status` (done/skipped/partial). + +## Development checklist +- [x] Wybrać framework (Flask) i zbudować UI demo. +- [ ] Dodać endpointy OAuth (`/auth/login`, `/oauth/callback`). +- [ ] Zaimplementować przechowywanie/odświeżanie tokenów. +- [ ] Podłączyć klientów Google API (Gmail, Tasks, Calendar) zamiast mocków. +- [ ] Dodać CRUD na Habits + check-iny. +- [ ] Zintegrować realne dane z widokiem dashboardu. + +## Notes and constraints +- Demo używa danych przykładowych; produkcyjnie trzeba skonfigurować Google Cloud project i sekrety. +- Keep secrets out of version control; use environment variables or a secrets manager. +- When adding code, avoid try/catch around imports to keep import failures visible. diff --git a/app.py b/app.py new file mode 100644 index 0000000..0d835c9 --- /dev/null +++ b/app.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from dataclasses import dataclass +from datetime import datetime, timedelta +from typing import List + +from flask import Flask, render_template + +app = Flask(__name__) + + +@dataclass +class Email: + sender: str + subject: str + received_at: datetime + snippet: str + + +@dataclass +class Task: + title: str + due: datetime | None + status: str + + +@dataclass +class CalendarEvent: + title: str + starts_at: datetime + ends_at: datetime + location: str | None = None + + +@dataclass +class Habit: + name: str + streak: int + note: str | None = None + + +def mock_emails() -> List[Email]: + now = datetime.utcnow() + return [ + Email("team@project.io", "Sprint review notes", now - timedelta(hours=1), "Nagranie i notatki z wczoraj"), + Email("billing@saas.com", "Faktura czerwiec", now - timedelta(hours=5), "Dziękujemy za płatność"), + Email("alerts@monitoring.io", "Status page update", now - timedelta(days=1), "Wszystkie systemy operacyjne"), + ] + + +def mock_tasks() -> List[Task]: + tomorrow = datetime.utcnow() + timedelta(days=1) + return [ + Task("Przygotować dema dla klienta", tomorrow, "in-progress"), + Task("Zaplanować posty na bloga", None, "todo"), + Task("Domknąć sprint", tomorrow + timedelta(days=1), "todo"), + ] + + +def mock_events() -> List[CalendarEvent]: + today = datetime.utcnow().replace(hour=9, minute=0, second=0, microsecond=0) + return [ + CalendarEvent("Status tygodniowy", today, today + timedelta(hours=1), "Meet"), + CalendarEvent("Demo klienta", today + timedelta(hours=2), today + timedelta(hours=3), "Zoom"), + CalendarEvent("1:1", today + timedelta(hours=4), today + timedelta(hours=4, minutes=30)), + ] + + +def mock_habits() -> List[Habit]: + return [ + Habit("Ćwiczenia", 5, "Poranny trening 20 min"), + Habit("Pisanie dziennika", 12, "3 rzeczy za które jesteś wdzięczny"), + Habit("Nauka", 7, "30 minut kursu"), + ] + + +@app.route("/") +def home(): + return render_template( + "index.html", + emails=mock_emails(), + tasks=mock_tasks(), + events=mock_events(), + habits=mock_habits(), + ) + + +if __name__ == "__main__": + app.run(debug=True) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..95fef4e --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +Flask==3.0.3 diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..e2d7292 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,107 @@ + + + + + + Google Suite Hub (demo) + + + +

Google Suite Hub

+

Prosty, działający demo-front: Gmail, Tasks, Calendar i Habits z przykładowymi danymi.

+ +
+
+
Gmail
+ {% for email in emails %} +
+
{{ email.subject }}
+
Od: {{ email.sender }} · {{ email.received_at.strftime('%H:%M %d.%m') }}
+
{{ email.snippet }}
+
+ {% endfor %} +
+ +
+
Tasks
+ {% for task in tasks %} +
+
{{ task.title }}
+
+ Status: {{ task.status }} + {% if task.due %} · Termin: {{ task.due.strftime('%d.%m %H:%M') }}{% endif %} +
+
+ {% endfor %} +
+ +
+
Calendar
+ {% for event in events %} +
+
{{ event.title }}
+
+ {{ event.starts_at.strftime('%d.%m %H:%M') }} – {{ event.ends_at.strftime('%H:%M') }} + {% if event.location %} · {{ event.location }}{% endif %} +
+
+ {% endfor %} +
+ +
+
Habits
+ {% for habit in habits %} +
+
{{ habit.name }}
+
Seria: {{ habit.streak }} dni{% if habit.note %} · {{ habit.note }}{% endif %}
+
+ {% endfor %} +
+
+ +