From 788e182f295cd48377f0d919717dc6dc9f39baa5 Mon Sep 17 00:00:00 2001 From: theodorsm <theodor@midtlien.com> Date: Wed, 15 Mar 2023 15:46:52 +0100 Subject: [PATCH 1/3] Resolved merge conflict --- README.md | 39 +++++-- backend/Dockerfile | 2 +- backend/alembic.ini | 110 ++++++++++++++++++ backend/alembic/README | 1 + backend/alembic/env.py | 76 ++++++++++++ backend/alembic/script.py.mako | 24 ++++ .../versions/aa01c8290072_first_revision.py | 92 +++++++++++++++ backend/crud.py | 23 ++-- backend/database.py | 11 +- backend/main.py | 60 ++++++---- backend/model.py | 25 ++-- requirements.txt => backend/requirements.txt | 1 + docker-compose.yml | 15 ++- 13 files changed, 410 insertions(+), 69 deletions(-) create mode 100644 backend/alembic.ini create mode 100644 backend/alembic/README create mode 100644 backend/alembic/env.py create mode 100644 backend/alembic/script.py.mako create mode 100644 backend/alembic/versions/aa01c8290072_first_revision.py rename requirements.txt => backend/requirements.txt (94%) diff --git a/README.md b/README.md index 9488446..f4f88e3 100644 --- a/README.md +++ b/README.md @@ -26,25 +26,44 @@ Environment: Create this .env file in the root folder! -In the `.env` make sure that: +In the `backend` folder, create`.env` containing the following: - `production = false` - `SECRET_KEY` is set - the client secrets corresponds to your feide instance -In frontend: -- create `.env.development` with PUBLIC_API_URL="http://127.0.0.1:8000" => Create this in frontend folder! + +In `frontend` folder: +- create `.env.development` with PUBLIC_API_URL="http://127.0.0.1:8000". + +#### Backend: Running backend: ```bash +cd backend python -m venv venv # only do once source ./venv/bin/activate pip install -r requirements.txt # Run the backend -uvicorn backend.main:app --reload +uvicorn main:app --reload # Running at 127.0.0.1:8000 ``` +**Migration**: alembic is used for databse migration (kind of git for databases). +You can read more about alembic [here](https://alembic.sqlalchemy.org/en/latest/tutorial.html), or take a look at this tutorial [video](https://www.youtube.com/watch?v=SdcH6IEi6nE&list=WL&index=6). + +When ANY changes is made to the database model file, then a migration has to happen. This is done by the following commands: + +```bash +# Create migration +alembic revision --autogenerate -m "Revision message, something relevant here" + +# Apply latest migration +alembic upgrade head +``` + +#### Frontend: + Running frontend: ```bash cd frontend @@ -68,13 +87,14 @@ Requirements: Environment: -In the `.env` make sure that: +In the `backend` folder, create`.env` containing the following: - `production = true` - `SECRET_KEY` is set - the client secrets corresponds to your feide instance - the following postgres variables is set: `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`. -In frontend: -- create `.env.production` with PUBLIC_API_URL="https://ref.iik.ntnu.no/api" in the frontend directory. + +In `frontend` folder: +- create `.env.production` with PUBLIC_API_URL="https://ref.iik.ntnu.no/api". Also make sure that there exists a `certs` folder with the ssl privatekey and certificate. @@ -100,8 +120,3 @@ Sometimes the volume of postgres needs to be deleted before running the containe ``` docker volume rm reflect_db-data ``` - - -## TODO - -- [ ] migration of database diff --git a/backend/Dockerfile b/backend/Dockerfile index 03a264a..5747dbb 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -14,4 +14,4 @@ EXPOSE 80 WORKDIR /build/ -CMD python -m uvicorn backend.main:app --host 0.0.0.0 --port 80 +CMD python -m uvicorn main:app --host 0.0.0.0 --port 80 diff --git a/backend/alembic.ini b/backend/alembic.ini new file mode 100644 index 0000000..00dd9ea --- /dev/null +++ b/backend/alembic.ini @@ -0,0 +1,110 @@ +# A generic, single database configuration. + +[alembic] +# path to migration scripts +script_location = alembic + +# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s +# Uncomment the line below if you want the files to be prepended with date and time +# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file +# for all available tokens +# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s + +# sys.path path, will be prepended to sys.path if present. +# defaults to the current working directory. +prepend_sys_path = . + +# timezone to use when rendering the date within the migration file +# as well as the filename. +# If specified, requires the python-dateutil library that can be +# installed by adding `alembic[tz]` to the pip requirements +# string value is passed to dateutil.tz.gettz() +# leave blank for localtime +# timezone = + +# max length of characters to apply to the +# "slug" field +# truncate_slug_length = 40 + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + +# set to 'true' to allow .pyc and .pyo files without +# a source .py file to be detected as revisions in the +# versions/ directory +# sourceless = false + +# version location specification; This defaults +# to alembic/versions. When using multiple version +# directories, initial revisions must be specified with --version-path. +# The path separator used here should be the separator specified by "version_path_separator" below. +# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions + +# version path separator; As mentioned above, this is the character used to split +# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep. +# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas. +# Valid values for version_path_separator are: +# +# version_path_separator = : +# version_path_separator = ; +# version_path_separator = space +version_path_separator = os # Use os.pathsep. Default configuration used for new projects. + +# set to 'true' to search source files recursively +# in each "version_locations" directory +# new in Alembic version 1.10 +# recursive_version_locations = false + +# the output encoding used when revision files +# are written from script.py.mako +# output_encoding = utf-8 + +# sqlalchemy.url = driver://user:pass@localhost/dbname + + +[post_write_hooks] +# post_write_hooks defines scripts or Python functions that are run +# on newly generated revision scripts. See the documentation for further +# detail and examples + +# format using "black" - use the console_scripts runner, against the "black" entrypoint +# hooks = black +# black.type = console_scripts +# black.entrypoint = black +# black.options = -l 79 REVISION_SCRIPT_FILENAME + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/backend/alembic/README b/backend/alembic/README new file mode 100644 index 0000000..98e4f9c --- /dev/null +++ b/backend/alembic/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/backend/alembic/env.py b/backend/alembic/env.py new file mode 100644 index 0000000..6d1b469 --- /dev/null +++ b/backend/alembic/env.py @@ -0,0 +1,76 @@ +from logging.config import fileConfig + +from alembic import context +from database import DATABASE_URL, Base +from sqlalchemy import engine_from_config, pool + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config +config.set_main_option("sqlalchemy.url", DATABASE_URL) + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +if config.config_file_name is not None: + fileConfig(config.config_file_name) + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +target_metadata = Base.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline() -> None: + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online() -> None: + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure(connection=connection, target_metadata=target_metadata) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/backend/alembic/script.py.mako b/backend/alembic/script.py.mako new file mode 100644 index 0000000..55df286 --- /dev/null +++ b/backend/alembic/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade() -> None: + ${upgrades if upgrades else "pass"} + + +def downgrade() -> None: + ${downgrades if downgrades else "pass"} diff --git a/backend/alembic/versions/aa01c8290072_first_revision.py b/backend/alembic/versions/aa01c8290072_first_revision.py new file mode 100644 index 0000000..f228de5 --- /dev/null +++ b/backend/alembic/versions/aa01c8290072_first_revision.py @@ -0,0 +1,92 @@ +"""First revision + +Revision ID: aa01c8290072 +Revises: +Create Date: 2023-03-10 14:33:14.535079 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'aa01c8290072' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('reflections') + op.drop_table('users') + op.drop_table('questions') + op.drop_table('course_question') + op.drop_table('units') + op.drop_table('enrollment') + op.drop_table('courses') + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('courses', + sa.Column('name', sa.VARCHAR(), nullable=True), + sa.Column('id', sa.VARCHAR(), nullable=False), + sa.Column('semester', sa.VARCHAR(), nullable=True), + sa.Column('responsible', sa.VARCHAR(), nullable=True), + sa.Column('website', sa.VARCHAR(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('enrollment', + sa.Column('user_email', sa.VARCHAR(), nullable=False), + sa.Column('course_id', sa.VARCHAR(), nullable=False), + sa.Column('role', sa.VARCHAR(length=18), nullable=False), + sa.ForeignKeyConstraint(['course_id'], ['courses.id'], ), + sa.ForeignKeyConstraint(['user_email'], ['users.email'], ), + sa.PrimaryKeyConstraint('user_email', 'course_id', 'role') + ) + op.create_table('units', + sa.Column('id', sa.INTEGER(), nullable=False), + sa.Column('seq_no', sa.INTEGER(), nullable=True), + sa.Column('title', sa.VARCHAR(), nullable=True), + sa.Column('date_available', sa.DATE(), nullable=True), + sa.Column('course_id', sa.VARCHAR(), nullable=True), + sa.ForeignKeyConstraint(['course_id'], ['courses.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('course_question', + sa.Column('course_id', sa.VARCHAR(), nullable=False), + sa.Column('question_id', sa.INTEGER(), nullable=False), + sa.ForeignKeyConstraint(['course_id'], ['courses.id'], ), + sa.ForeignKeyConstraint(['question_id'], ['questions.id'], ), + sa.PrimaryKeyConstraint('course_id', 'question_id') + ) + op.create_table('questions', + sa.Column('id', sa.INTEGER(), nullable=False), + sa.Column('question', sa.VARCHAR(), nullable=True), + sa.Column('comment', sa.VARCHAR(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('users', + sa.Column('email', sa.VARCHAR(), nullable=False), + sa.PrimaryKeyConstraint('email'), + sa.UniqueConstraint('email') + ) + op.create_table('reflections', + sa.Column('id', sa.INTEGER(), nullable=False), + sa.Column('body', sa.VARCHAR(), nullable=True), + sa.Column('timestamp', sa.DATE(), nullable=True), + sa.Column('category', sa.VARCHAR(), nullable=True), + sa.Column('is_interesting', sa.BOOLEAN(), nullable=True), + sa.Column('is_problematic', sa.BOOLEAN(), nullable=True), + sa.Column('is_sorted', sa.BOOLEAN(), nullable=True), + sa.Column('user_id', sa.VARCHAR(), nullable=True), + sa.Column('unit_id', sa.INTEGER(), nullable=True), + sa.Column('question_id', sa.INTEGER(), nullable=True), + sa.ForeignKeyConstraint(['question_id'], ['questions.id'], ), + sa.ForeignKeyConstraint(['unit_id'], ['units.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['users.email'], ), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### diff --git a/backend/crud.py b/backend/crud.py index 5675888..31cee47 100644 --- a/backend/crud.py +++ b/backend/crud.py @@ -1,9 +1,9 @@ from datetime import datetime +import model +import schemas from sqlalchemy.orm import Session -from . import model, schemas - @@ -19,14 +19,17 @@ def create_user(db: Session, user_email: str): db.refresh(db_user) return db_user -def create_enrollment(db: Session, user_email: str, course_id: str, role: str ): - - #getting student + +def create_enrollment(db: Session, user_email: str, course_id: str, role: str): + + # getting student db_user = get_user(db, user_email=user_email) - #getting course + # getting course db_course = get_course(db, course_id=course_id) - #Creating enrollment - db_enrollment = model.Enrollment(user_email=user_email, course_id=course_id, role=role) + # Creating enrollment + db_enrollment = model.Enrollment( + user_email=user_email, course_id=course_id, role=role + ) print(db_enrollment) print("Creating enrollment") db.add(db_enrollment) @@ -46,7 +49,6 @@ def create_question(db: Session, question: str, comment: str): return db_obj - def create_course(db: Session, course: schemas.CourseCreate): db_course = model.Course(**course) questions = [ @@ -69,6 +71,7 @@ def create_course(db: Session, course: schemas.CourseCreate): db.refresh(db_course) return db_course + # def enroll_user_to_course(db: Session, course_id: str, user_email: str): # db_course = get_course(db, course_id=course_id) # db_user: schemas.User = get_user(db, user_email = user_email) @@ -138,4 +141,4 @@ def get_number_of_unit_questions(db: Session, unit_id: int ): #mulig man må bruke id, fordi seq no ikke er unikt #def get_unit(db: Session, id: int): - # return db.query(model.Unit).filter(model.Unit.id == id).first() \ No newline at end of file + # return db.query(model.Unit).filter(model.Unit.id == id).first() diff --git a/backend/database.py b/backend/database.py index 17e63a0..a1f1ad9 100644 --- a/backend/database.py +++ b/backend/database.py @@ -1,20 +1,23 @@ -import databases +# import databases from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from starlette.config import Config +from starlette.datastructures import Secret config = Config(".env") +postgres_user = str(config("POSTGRES_USER", cast=Secret)) +postgres_pass = str(config("POSTGRES_PASSWORD", cast=Secret)) if config("production", cast=bool, default=False): DATABASE_URL = ( - "postgresql://postgres:thissentenceissupersecure@reflect_db_1:5432/reflect" + f"postgresql://{postgres_user}:{postgres_pass}@reflect_db_1:5432/reflect" ) - database = databases.Database(DATABASE_URL) + # database = databases.Database(DATABASE_URL) engine = create_engine(DATABASE_URL) else: DATABASE_URL = "sqlite:///./reflect.db" - database = databases.Database(DATABASE_URL) + # database = databases.Database(DATABASE_URL) engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False}) diff --git a/backend/main.py b/backend/main.py index f8b547b..d3160c1 100644 --- a/backend/main.py +++ b/backend/main.py @@ -7,22 +7,23 @@ from typing import List, Optional import requests from requests.structures import CaseInsensitiveDict +import crud +import model import motor.motor_asyncio +import schemas from authlib.integrations.starlette_client import OAuth, OAuthError +from database import SessionLocal, engine from fastapi import Depends, FastAPI, Form, HTTPException, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates -from sqlalchemy.orm import Session from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import Session from starlette.config import Config from starlette.datastructures import Secret from starlette.middleware.sessions import SessionMiddleware -from starlette.responses import RedirectResponse,Response - -from . import crud, model, schemas -from .database import SessionLocal, engine +from starlette.responses import RedirectResponse, Response if os.path.exists("./reflect.db"): os.remove("./reflect.db") @@ -48,14 +49,14 @@ app.add_middleware( allow_methods=["*"], ) -templates = Jinja2Templates(directory="backend/templates") -app.mount("/static", StaticFiles(directory="backend/static"), name="static") +templates = Jinja2Templates(directory="templates") +app.mount("/static", StaticFiles(directory="static"), name="static") if config("production", cast=bool, default=False): REDIRECT_URI = "https://ref2.iik.ntnu.no/auth" BASE_URL = "https://ref2.iik.ntnu.no" else: - REDIRECT_URI = "https://localhost/auth" + REDIRECT_URI = "http://localhost/auth" BASE_URL = "http://127.0.0.1:5173" course_id: str = "TDT4100" @@ -102,7 +103,9 @@ def start_db(): print("init database") db = SessionLocal() - course = crud.create_course(db, course={"name": course_name, "id": course_id, "semester": semester}) + course = crud.create_course( + db, course={"name": course_name, "id": course_id, "semester": semester} + ) user = crud.create_user(db, user_email="thomas@test.no") user0 = crud.create_user(db, user_email="eivind@test.no") user1 = crud.create_user(db, user_email="jørgen@test.no") @@ -159,7 +162,9 @@ def start_db(): # } # crud.create_reflection(db=db, reflection=ref) - enrollment = crud.create_enrollment(course_id="TDT4100", db=db, role="student", user_email="thomas@test.no") + enrollment = crud.create_enrollment( + course_id="TDT4100", db=db, role="student", user_email="thomas@test.no" + ) db.commit() db.close() @@ -167,7 +172,8 @@ def start_db(): @app.get("/login") async def login(request: Request): return await oauth.feide.authorize_redirect(request, REDIRECT_URI) - + + @app.get("/auth") async def auth(request: Request, db: Session = Depends(get_db)): try: @@ -218,13 +224,16 @@ async def course(request: Request, db: Session = Depends(get_db)): print(course) return course + @app.get("/getcourse", response_model=schemas.Course) -async def course(request: Request, course_id: str = 'ttm4175', db: Session = Depends(get_db)): +async def course( + request: Request, course_id: str = "ttm4175", db: Session = Depends(get_db) +): if not is_logged_in(request): raise HTTPException(401, detail="You are not logged in ") course = crud.get_course(db, course_id=course_id) - if(course is None): + if course is None: raise HTTPException(404, detail="Course not found") return course @@ -238,24 +247,31 @@ async def user(request: Request, db: Session = Depends(get_db)): user = request.session.get("user") email: str = user.get("eduPersonPrincipalName") user = crud.get_user(db, user_email=email) - if(user == None): - request.session.pop('user') + if user == None: + request.session.pop("user") raise HTTPException(404, detail="User not found") - + return user + # enroll user in course @app.post("/enroll_user", response_model=schemas.EnrollmentBase) -async def enroll(request: Request, ref: schemas.EnrollmentCreate, db: Session = Depends(get_db)): +async def enroll( + request: Request, ref: schemas.EnrollmentCreate, db: Session = Depends(get_db) +): if not is_logged_in(request): raise HTTPException(401, detail="You are not logged in ") - try: - return crud.create_enrollment(db, role=ref.role, course_id=ref.course_id, user_email=ref.user_email) + try: + return crud.create_enrollment( + db, role=ref.role, course_id=ref.course_id, user_email=ref.user_email + ) except IntegrityError: - raise HTTPException(409, detail="User already enrolled with this course and role") - + raise HTTPException( + 409, detail="User already enrolled with this course and role" + ) + @app.post("/create_course", response_model=schemas.Course) async def create_reflection( @@ -265,7 +281,7 @@ async def create_reflection( raise HTTPException(401, detail="You are not logged in") try: return crud.create_course(db, course=ref.dict()) - + except IntegrityError: raise HTTPException(409, detail="Course already exists") diff --git a/backend/model.py b/backend/model.py index 7172463..e842d6d 100644 --- a/backend/model.py +++ b/backend/model.py @@ -1,10 +1,9 @@ -from sqlalchemy import Boolean, Column, Date, ForeignKey, Integer, String, Enum +from database import Base +from sqlalchemy import Boolean, Column, Date, Enum, ForeignKey, Integer, String from sqlalchemy.orm import relationship from sqlalchemy.schema import ForeignKeyConstraint, Table -from .database import Base - -#Course question (specify a relationship between a course and a question) +# Course question (specify a relationship between a course and a question) course_question = Table( "course_question", Base.metadata, @@ -12,7 +11,8 @@ course_question = Table( Column("question_id", ForeignKey("questions.id"), primary_key=True), ) -enum_values = Enum('lecturer', 'teaching assistant', 'student') +enum_values = Enum("lecturer", "teaching assistant", "student") + class Enrollment(Base): __tablename__ = "enrollment" @@ -24,12 +24,11 @@ class Enrollment(Base): user = relationship("User", back_populates="enrollments") course = relationship("Course", back_populates="users") + class User(Base): __tablename__ = "users" - email = Column(String, unique=True, primary_key = True) - enrollments = relationship( - "Enrollment", back_populates="user" - ) + email = Column(String, unique=True, primary_key=True) + enrollments = relationship("Enrollment", back_populates="user") reflections = relationship("Reflection", back_populates="user") @@ -42,11 +41,9 @@ class Course(Base): semester = Column(String) responsible = Column(String, default="") website = Column(String, default="") - + units = relationship("Unit", back_populates="course") - users = relationship( - "Enrollment",back_populates="course" - ) + users = relationship("Enrollment", back_populates="course") questions = relationship( "Question", secondary=course_question, back_populates="courses" ) @@ -89,4 +86,4 @@ class Reflection(Base): user = relationship("User", back_populates="reflections") unit_id = Column(Integer, ForeignKey("units.id")) unit = relationship("Unit", back_populates="reflections") - question_id = Column(Integer, ForeignKey("questions.id")) \ No newline at end of file + question_id = Column(Integer, ForeignKey("questions.id")) diff --git a/requirements.txt b/backend/requirements.txt similarity index 94% rename from requirements.txt rename to backend/requirements.txt index e2f985d..fd9e313 100644 --- a/requirements.txt +++ b/backend/requirements.txt @@ -14,3 +14,4 @@ databases aiosqlite asyncpg psycopg2 +alembic diff --git a/docker-compose.yml b/docker-compose.yml index 5afb791..08f8517 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,15 +21,17 @@ services: volumes: - db-data:/var/lib/postgresql/data/pgdata env_file: - - .env + - ./backend/.env environment: - PGDATA=/var/lib/postgresql/data/pgdata frontend: - image: reflect-frontend + image: + reflect-frontend # network_mode: "host" build: context: ./frontend - dockerfile: Dockerfile + dockerfile: + Dockerfile # ports: # - 5173:3000 labels: @@ -40,10 +42,11 @@ services: - "traefik.port=3000" backend: image: reflect - #network_mode: "host" + #network_mode: "host" build: - context: . - dockerfile: backend/Dockerfile + context: ./backend + dockerfile: + Dockerfile # ports: # - 8000:80 env_file: -- GitLab From 95e4627b1e2a64a916a9b1f0233ae5e0f94200a1 Mon Sep 17 00:00:00 2001 From: theodorsm <theodor@midtlien.com> Date: Wed, 15 Mar 2023 15:48:19 +0100 Subject: [PATCH 2/3] Resolved merge conflict --- README.md | 4 +- assistant-categorize.html | 200 ----- backend/database.py | 2 +- backend/main.py | 28 +- backend/model.py | 2 +- docker-compose.yml | 6 +- frontend/Dockerfile | 12 + frontend/package-lock.json | 226 +++++ frontend/package.json | 1 + frontend/svelte.config.js | 2 +- package-lock.json | 1599 ------------------------------------ package.json | 7 - traefik.yaml | 4 +- 13 files changed, 265 insertions(+), 1828 deletions(-) delete mode 100644 assistant-categorize.html create mode 100644 frontend/Dockerfile delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/README.md b/README.md index f4f88e3..bd3c539 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,6 @@ Environment: `.env` is not commited to this repo because of security, so this file has to be created. -Create this .env file in the root folder! - In the `backend` folder, create`.env` containing the following: - `production = false` - `SECRET_KEY` is set @@ -92,6 +90,8 @@ In the `backend` folder, create`.env` containing the following: - `SECRET_KEY` is set - the client secrets corresponds to your feide instance - the following postgres variables is set: `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`. +- REDIRECT_URI = "https://ref2.iik.ntnu.no/auth" +- BASE_URL = "https://ref2.iik.tnun.no" In `frontend` folder: - create `.env.production` with PUBLIC_API_URL="https://ref.iik.ntnu.no/api". diff --git a/assistant-categorize.html b/assistant-categorize.html deleted file mode 100644 index c438490..0000000 --- a/assistant-categorize.html +++ /dev/null @@ -1,200 +0,0 @@ -{% extends "base.html" %} -{% block body %} -<main class="flex-shrink-0"> - <div class="container"> - - <div class="card mt-5 mb-5" style="width: 100%;"> - <div class="card-header"> - <div class="fs-5 fw-bold"> - Problems with state machines - </div> - </div> - <div class="list-group list-group-flush fst-italic"> - <a href="#" class="list-group-item list-group-item-action" aria-current="true"> - The current link item - </a> - <a href="#" class="list-group-item list-group-item-action list-group-item-success">A second link item, - flagged as interesting.</a> - <a href="#" class="list-group-item list-group-item-action muted"> - This is a text with a reflection of a user. I don't understand anything of what - the lecture said. - </a> - <a href="#" class="list-group-item list-group-item-action list-group-item-danger">A fourth link item, - flagged as problematic.</a> - </div> - </div> - - - <form class="mt-5 mb-5" action="store" method="post"> - <div class="card mt-5 mb-5" style="width: 100%;"> - <div class="card-header"> - Reflection 3 / 54 - </div> - <ul class="list-group list-group-flush"> - <li class="list-group-item p-4"> - <p class="text-muted"> - <b>Clearest Insight:</b> What did you learn in this unit? What was your clearest insight, or - your best learing - achievement? - </p> - <textarea disabled placeholder="Write one or two sentences..." - class="form-control bg-light border-1 disabled" id="best" name="best" - rows="5">This is a text with a reflection of a user. I don't understand anything of what the lecture said. This is a text with a reflection of a user. I don't understand anything of what the lecture said.</textarea> - </li> - - <li class="list-group-item p-4"> - - <!--<p class="text-muted">Assign the reflection to a category.</p>--> - - <div class="row g-3 align-items-center flex-nowrap"> - <div class="col-auto"> - <input class="form-check-input" type="radio" name="category" id="flexRadioDefault2" - value="category_new" checked> - </div> - <div class="col-auto" style="width:80%"> - <input type="text" id="inputPassword6" class="form-control" name="new_category_text" - aria-describedby="passwordHelpInline" disabled value="Default Label (unassigned)"> - </div> - </div> - - <div class="row g-3 align-items-center flex-nowrap mt-1"> - <div class="col-auto"> - <input class="form-check-input" type="radio" name="category" id="flexRadioDefault2" - value="category_new"> - </div> - <div class="col-auto" style="width:80%"> - <input type="text" id="inputPassword6" class="form-control" name="new_category_text" - aria-describedby="passwordHelpInline" disabled - value="State machines and deferring elements"> - </div> - </div> - - <div class="row g-3 align-items-center flex-nowrap mt-1"> - <div class="col-auto"> - <input class="form-check-input" type="radio" name="category" id="flexRadioDefault2" - value="category_new"> - </div> - <div class="col-auto" style="width:80%"> - <input type="text" id="inputPassword6" class="form-control" name="new_category_text" - aria-describedby="passwordHelpInline" disabled value="Sequence diagrams"> - </div> - </div> - - <div class="row g-3 align-items-center flex-nowrap mt-1"> - <div class="col-auto"> - <input class="form-check-input" type="radio" name="category" id="flexRadioDefault2" - value="category_new"> - </div> - <div class="col-auto" style="width:80%"> - <input type="text" id="inputPassword6" class="form-control" name="new_category_text" - aria-describedby="passwordHelpInline" disabled - value="Could not install the software"> - </div> - </div> - - <div class="row g-3 align-items-center flex-nowrap mt-1"> - <div class="col-auto"> - <input class="form-check-input" type="radio" name="category" id="flexRadioDefault2" - value="category_new"> - </div> - <div class="col-auto" style="width:80%"> - <input type="text" id="inputPassword6" class="form-control" name="new_category_text" - aria-describedby="passwordHelpInline" placeholder="Create new..."> - </div> - </div> - </li> - - <li class="list-group-item p-4"> - <div class="form-check"> - <input class="form-check-input" type="checkbox" id="interesting" name="interesting"> - <label class="form-check-label" for="interesting"> - Flag as interesting or representative - </label> - </div> - <div class="form-check"> - <input class="form-check-input" type="checkbox" id="problematic" name="problematic"> - <label class="form-check-label" for="problematic"> - Flag as problematic - </label> - </div> - - </li> - - - - </ul> - <div class="card-footer p-4"> - <button type="submit" class="btn btn-primary shadow-sm end-0 position-sticky">Save</button> - <button type="submit" class="btn btn-link end-0 position-sticky">Cancel</button> - </div> - </div> - </form> - - - - - - - <div class="list-group mt-5 mb-5"> - - <div class="list-group-item list-group-item-action"> - <div class="d-flex w-100 justify-content-between"> - <h5 class="mb-1">Unit 1: State Machines</h5> - <small class="text-muted">54 reflections</small> - </div> - <div class="d-flex w-100 justify-content-between"> - <a href="#">Læringsprestasjon</a> - <small class="text-muted">3 unassigned</small> - </div> - <div class="d-flex w-100 justify-content-between"> - <a href="#">Vanskeligst</a> - <small class="text-muted">3 unassigned</small> - </div> - </div> - <div class="list-group-item list-group-item-action"> - <div class="d-flex w-100 justify-content-between"> - <h5 class="mb-1">Unit 2: State Machines</h5> - <small class="text-muted">54 reflections</small> - </div> - <div class="d-flex w-100 justify-content-between"> - <a href="#">Læringsprestasjon</a> - <small class="text-muted">3 unassigned</small> - </div> - <div class="d-flex w-100 justify-content-between"> - <a href="#">Vanskeligst</a> - <small class="text-muted">3 unassigned</small> - </div> - </div> - <div class="list-group-item list-group-item-action"> - <div class="d-flex w-100 justify-content-between"> - <h5 class="mb-1">Unit 3: State Machines</h5> - <small class="text-muted">54 reflections</small> - </div> - <div class="d-flex w-100 justify-content-between"> - <a href="#">Læringsprestasjon</a> - <small class="text-muted">3 unassigned</small> - </div> - <div class="d-flex w-100 justify-content-between"> - <a href="#">Vanskeligst</a> - <small class="text-muted">3 unassigned</small> - </div> - </div> - <div class="list-group-item list-group-item-action"> - <div class="d-flex w-100 justify-content-between"> - <h5 class="mb-1">Unit 4: State Machines</h5> - <small class="text-muted">54 reflections</small> - </div> - <div class="d-flex w-100 justify-content-between"> - <a href="#">Læringsprestasjon</a> - <small class="text-muted">3 unassigned</small> - </div> - <div class="d-flex w-100 justify-content-between"> - <a href="#">Vanskeligst</a> - <small class="text-muted">3 unassigned</small> - </div> - </div> - </div> - </div> - -</main> -{% endblock %} \ No newline at end of file diff --git a/backend/database.py b/backend/database.py index a1f1ad9..bc14bba 100644 --- a/backend/database.py +++ b/backend/database.py @@ -11,7 +11,7 @@ postgres_pass = str(config("POSTGRES_PASSWORD", cast=Secret)) if config("production", cast=bool, default=False): DATABASE_URL = ( - f"postgresql://{postgres_user}:{postgres_pass}@reflect_db_1:5432/reflect" + f"postgresql://{postgres_user}:{postgres_pass}@ntnu_reflect_db_1:5432/reflect" ) # database = databases.Database(DATABASE_URL) engine = create_engine(DATABASE_URL) diff --git a/backend/main.py b/backend/main.py index d3160c1..c1b5ef3 100644 --- a/backend/main.py +++ b/backend/main.py @@ -53,8 +53,8 @@ templates = Jinja2Templates(directory="templates") app.mount("/static", StaticFiles(directory="static"), name="static") if config("production", cast=bool, default=False): - REDIRECT_URI = "https://ref2.iik.ntnu.no/auth" - BASE_URL = "https://ref2.iik.ntnu.no" + REDIRECT_URI = config("REDIRECT_URI", cast=str) + BASE_URL = config("BASE_URL", cast=str) else: REDIRECT_URI = "http://localhost/auth" BASE_URL = "http://127.0.0.1:5173" @@ -209,9 +209,12 @@ async def create_reflection( if not is_logged_in(request): raise HTTPException(401, detail="You are not logged in") number_of_questions = crud.get_number_of_unit_questions(db, ref.unit_id) - if len(crud.get_reflections(db, ref.user_id, ref.unit_id)) > number_of_questions - 1: - raise HTTPException(403, detail="You have already reflected this unit") - + if ( + len(crud.get_reflections(db, ref.user_id, ref.unit_id)) + > number_of_questions - 1 + ): + raise HTTPException(403, detail="You have already reflected this unit") + return crud.create_reflection(db, reflection=ref.dict()) @@ -285,21 +288,22 @@ async def create_reflection( except IntegrityError: raise HTTPException(409, detail="Course already exists") + @app.post("/create_unit", response_model=schemas.Unit) async def create_unit( request: Request, ref: schemas.UnitCreate, db: Session = Depends(get_db) ): if not is_logged_in(request): raise HTTPException(401, detail="You are not logged in") - + try: seq_number = int(ref.seq_no) return crud.create_unit( - db=db, - title=ref.title, - date_available=ref.date_available, - seq_no=seq_number, - course_id=ref.course_id, - ) + db=db, + title=ref.title, + date_available=ref.date_available, + seq_no=seq_number, + course_id=ref.course_id, + ) except IntegrityError: raise HTTPException(409, detail="unit already exists") diff --git a/backend/model.py b/backend/model.py index e842d6d..2dfe5d9 100644 --- a/backend/model.py +++ b/backend/model.py @@ -11,7 +11,7 @@ course_question = Table( Column("question_id", ForeignKey("questions.id"), primary_key=True), ) -enum_values = Enum("lecturer", "teaching assistant", "student") +enum_values = Enum("lecturer", "teaching assistant", "student", name="enrollment_roles") class Enrollment(Base): diff --git a/docker-compose.yml b/docker-compose.yml index 08f8517..5aa8601 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,7 +36,7 @@ services: # - 5173:3000 labels: - "traefik.enable=true" - - "traefik.http.routers.frontend.rule=Host(`ref.iik.ntnu.no`)" + - "traefik.http.routers.frontend.rule=Host(`ref2.iik.ntnu.no`)" - "traefik.http.routers.frontend.tls=true" - "traefik.http.routers.frontend.entrypoints=websecure" - "traefik.port=3000" @@ -50,10 +50,10 @@ services: # ports: # - 8000:80 env_file: - - .env + - ./backend/.env labels: - "traefik.enable=true" - - "traefik.http.routers.backend.rule=Host(`ref.iik.ntnu.no`) && PathPrefix(`/api`) || Host(`ref.iik.ntnu.no`) && PathPrefix(`/auth`) " + - "traefik.http.routers.backend.rule=Host(`ref2.iik.ntnu.no`) && PathPrefix(`/api`) || Host(`ref2.iik.ntnu.no`) && PathPrefix(`/auth`) " - "traefik.http.routers.backend.tls=true" - "traefik.http.routers.backend.entrypoints=websecure" - "traefik.http.middlewares.backend-strip.stripprefix.prefixes=/api" diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..e2f43f0 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,12 @@ +FROM node:16-alpine + +WORKDIR /app +COPY . . +RUN npm install +RUN npm run build + +CMD ["node", "build"] +# CMD ["npm", "run", "dev", "--" , "--host", "3000"] +# CMD ["npm", "run", "dev", "--", "--host"] + +EXPOSE 3000 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b569e88..4428caa 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -19,6 +19,7 @@ "@rgossiaux/svelte-headlessui": "^1.0.2", "@skeletonlabs/skeleton": "^0.124.2", "@sveltejs/adapter-auto": "^2.0.0", + "@sveltejs/adapter-node": "^1.2.2", "@sveltejs/kit": "^1.5.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", @@ -553,6 +554,150 @@ "svelte": "^3.44.0" } }, + "node_modules/@rollup/plugin-commonjs": { + "version": "24.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.1.tgz", + "integrity": "sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.27.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.0.0.tgz", + "integrity": "sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.1.tgz", + "integrity": "sha512-ReY88T7JhJjeRVbfCyNj+NXAG3IIsVMsX9b5/9jC98dRP8/yxlZdz7mHZbHk5zHr24wZZICS5AcXsFZAXYUQEg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.0", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@skeletonlabs/skeleton": { "version": "0.124.2", "resolved": "https://registry.npmjs.org/@skeletonlabs/skeleton/-/skeleton-0.124.2.tgz", @@ -574,6 +719,21 @@ "@sveltejs/kit": "^1.0.0" } }, + "node_modules/@sveltejs/adapter-node": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-1.2.2.tgz", + "integrity": "sha512-HA+QPRve97ZAQfZ0wkHjtoSR9ilyYZV82T7zRgzm2WJ0rIpAgyRYf6K7KNwiCq23KKkN0hZHY5elNyCnVz8zrA==", + "dev": true, + "dependencies": { + "@rollup/plugin-commonjs": "^24.0.0", + "@rollup/plugin-json": "^6.0.0", + "@rollup/plugin-node-resolve": "^15.0.1", + "rollup": "^3.7.0" + }, + "peerDependencies": { + "@sveltejs/kit": "^1.0.0" + } + }, "node_modules/@sveltejs/kit": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.7.1.tgz", @@ -660,6 +820,12 @@ "integrity": "sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==", "dev": true }, + "node_modules/@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -678,6 +844,12 @@ "integrity": "sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==", "dev": true }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, "node_modules/@types/sass": { "version": "1.43.1", "resolved": "https://registry.npmjs.org/@types/sass/-/sass-1.43.1.tgz", @@ -1124,6 +1296,18 @@ "node": "*" } }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -1275,6 +1459,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1730,6 +1920,12 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -2114,6 +2310,21 @@ "node": ">=8" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-core-module": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", @@ -2147,6 +2358,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2165,6 +2382,15 @@ "node": ">=8" } }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 2b0f28f..e5cc464 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,6 +19,7 @@ "@rgossiaux/svelte-headlessui": "^1.0.2", "@skeletonlabs/skeleton": "^0.124.2", "@sveltejs/adapter-auto": "^2.0.0", + "@sveltejs/adapter-node": "^1.2.2", "@sveltejs/kit": "^1.5.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", diff --git a/frontend/svelte.config.js b/frontend/svelte.config.js index 0508916..42320d0 100644 --- a/frontend/svelte.config.js +++ b/frontend/svelte.config.js @@ -1,4 +1,4 @@ -import adapter from '@sveltejs/adapter-auto'; +import adapter from '@sveltejs/adapter-node'; import { vitePreprocess } from '@sveltejs/kit/vite'; /** @type {import('@sveltejs/kit').Config} */ diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 7e8b16b..0000000 --- a/package-lock.json +++ /dev/null @@ -1,1599 +0,0 @@ -{ - "name": "NTNU_reflect", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "devDependencies": { - "@tailwindcss/forms": "^0.5.3", - "prettier": "^2.8.4", - "prettier-plugin-tailwindcss": "^0.2.3" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "peer": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "peer": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", - "dev": true, - "dependencies": { - "mini-svg-data-uri": "^1.2.3" - }, - "peerDependencies": { - "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" - } - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "peer": true, - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "peer": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, - "peer": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "peer": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "peer": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "peer": true - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "peer": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "dev": true, - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", - "dev": true, - "peer": true, - "dependencies": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "detective": "bin/detective.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "peer": true - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, - "peer": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "peer": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "peer": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "peer": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "peer": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true, - "peer": true - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "peer": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "peer": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "peer": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "peer": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "peer": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "peer": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mini-svg-data-uri": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", - "dev": true, - "bin": { - "mini-svg-data-uri": "cli.js" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "peer": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true, - "peer": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "peer": true, - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", - "dev": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, - "peer": true, - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dev": true, - "peer": true, - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", - "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", - "dev": true, - "peer": true, - "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "dev": true, - "peer": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "peer": true - }, - "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-plugin-tailwindcss": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.3.tgz", - "integrity": "sha512-s2N5Dh7Ao5KTV1mao5ZBnn8EKtUcDPJEkGViZIjI0Ij9TTI5zgTz4IHOxW33jOdjHKa8CSjM88scelUiC5TNRQ==", - "dev": true, - "engines": { - "node": ">=12.17.0" - }, - "peerDependencies": { - "@ianvs/prettier-plugin-sort-imports": "*", - "@prettier/plugin-php": "*", - "@prettier/plugin-pug": "*", - "@shopify/prettier-plugin-liquid": "*", - "@shufo/prettier-plugin-blade": "*", - "@trivago/prettier-plugin-sort-imports": "*", - "prettier": ">=2.2.0", - "prettier-plugin-astro": "*", - "prettier-plugin-css-order": "*", - "prettier-plugin-import-sort": "*", - "prettier-plugin-jsdoc": "*", - "prettier-plugin-organize-attributes": "*", - "prettier-plugin-organize-imports": "*", - "prettier-plugin-style-order": "*", - "prettier-plugin-svelte": "*", - "prettier-plugin-twig-melody": "*" - }, - "peerDependenciesMeta": { - "@ianvs/prettier-plugin-sort-imports": { - "optional": true - }, - "@prettier/plugin-php": { - "optional": true - }, - "@prettier/plugin-pug": { - "optional": true - }, - "@shopify/prettier-plugin-liquid": { - "optional": true - }, - "@shufo/prettier-plugin-blade": { - "optional": true - }, - "@trivago/prettier-plugin-sort-imports": { - "optional": true - }, - "prettier-plugin-astro": { - "optional": true - }, - "prettier-plugin-css-order": { - "optional": true - }, - "prettier-plugin-import-sort": { - "optional": true - }, - "prettier-plugin-jsdoc": { - "optional": true - }, - "prettier-plugin-organize-attributes": { - "optional": true - }, - "prettier-plugin-organize-imports": { - "optional": true - }, - "prettier-plugin-style-order": { - "optional": true - }, - "prettier-plugin-svelte": { - "optional": true - }, - "prettier-plugin-twig-melody": { - "optional": true - } - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "peer": true, - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "peer": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "peer": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "peer": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "peer": true, - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwindcss": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.7.tgz", - "integrity": "sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==", - "dev": true, - "peer": true, - "dependencies": { - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "detective": "^5.2.1", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "lilconfig": "^2.0.6", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.0.9", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "peer": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "peer": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 6" - } - } - }, - "dependencies": { - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "peer": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "peer": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "peer": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", - "dev": true, - "requires": { - "mini-svg-data-uri": "^1.2.3" - } - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "peer": true - }, - "acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "peer": true, - "requires": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "peer": true - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "peer": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, - "peer": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "peer": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "peer": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "peer": true - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "peer": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "peer": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "peer": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "peer": true - }, - "defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "dev": true, - "peer": true - }, - "detective": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", - "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", - "dev": true, - "peer": true, - "requires": { - "acorn-node": "^1.8.2", - "defined": "^1.0.0", - "minimist": "^1.2.6" - } - }, - "didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "peer": true - }, - "dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, - "peer": true - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "peer": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "peer": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "peer": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "peer": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true, - "peer": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true, - "peer": true - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "peer": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "peer": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "peer": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "peer": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "peer": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "peer": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "peer": true - }, - "lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", - "dev": true, - "peer": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "peer": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "peer": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mini-svg-data-uri": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", - "dev": true - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "peer": true - }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "peer": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "peer": true - }, - "object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "peer": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "peer": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true, - "peer": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "peer": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "peer": true - }, - "postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "dev": true, - "peer": true, - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", - "dev": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - } - }, - "postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, - "peer": true, - "requires": { - "camelcase-css": "^2.0.1" - } - }, - "postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dev": true, - "peer": true, - "requires": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - } - }, - "postcss-nested": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", - "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", - "dev": true, - "peer": true, - "requires": { - "postcss-selector-parser": "^6.0.10" - } - }, - "postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "dev": true, - "peer": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "peer": true - }, - "prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", - "dev": true - }, - "prettier-plugin-tailwindcss": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.3.tgz", - "integrity": "sha512-s2N5Dh7Ao5KTV1mao5ZBnn8EKtUcDPJEkGViZIjI0Ij9TTI5zgTz4IHOxW33jOdjHKa8CSjM88scelUiC5TNRQ==", - "dev": true, - "requires": {} - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "peer": true - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "peer": true - }, - "read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "peer": true, - "requires": { - "pify": "^2.3.0" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "peer": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "peer": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "peer": true - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "peer": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "peer": true - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "peer": true - }, - "tailwindcss": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.7.tgz", - "integrity": "sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==", - "dev": true, - "peer": true, - "requires": { - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "detective": "^5.2.1", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "lilconfig": "^2.0.6", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.0.9", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "peer": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "peer": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "peer": true - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "peer": true - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index c8b9ed3..0000000 --- a/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "devDependencies": { - "@tailwindcss/forms": "^0.5.3", - "prettier": "^2.8.4", - "prettier-plugin-tailwindcss": "^0.2.3" - } -} diff --git a/traefik.yaml b/traefik.yaml index 32367b7..0726d13 100644 --- a/traefik.yaml +++ b/traefik.yaml @@ -45,8 +45,8 @@ entryPoints: tls: certificates: - - certFile: /certs/ref_iik_ntnu_no.pem - keyFile: /certs/PRIV_NONPASS.key + - certFile: /certs/ref2_iik_ntnu_no.pem + keyFile: /certs/ref2PRIVATEKEY_nopass.key # when testing certs, enable this so traefik doesn't use # it's own self signed. By default if it can't find a matching # cert, it'll just create it's own which will cause cert warnings -- GitLab From d8fdf1756ff6929e93efdc1c1900da6830e4c853 Mon Sep 17 00:00:00 2001 From: theodorsm <theodor@midtlien.com> Date: Wed, 15 Mar 2023 18:07:16 +0100 Subject: [PATCH 3/3] Fix migrations --- backend/alembic.ini | 2 +- backend/alembic/env.py | 9 +- backend/alembic/versions/9b1fabdaa344_init.py | 92 +++++++++++++++++++ .../versions/aa01c8290072_first_revision.py | 92 ------------------- 4 files changed, 100 insertions(+), 95 deletions(-) create mode 100644 backend/alembic/versions/9b1fabdaa344_init.py delete mode 100644 backend/alembic/versions/aa01c8290072_first_revision.py diff --git a/backend/alembic.ini b/backend/alembic.ini index 00dd9ea..42cab18 100644 --- a/backend/alembic.ini +++ b/backend/alembic.ini @@ -60,7 +60,7 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne # are written from script.py.mako # output_encoding = utf-8 -# sqlalchemy.url = driver://user:pass@localhost/dbname +sqlalchemy.url = sqlite:///./reflect.db [post_write_hooks] diff --git a/backend/alembic/env.py b/backend/alembic/env.py index 6d1b469..c00e201 100644 --- a/backend/alembic/env.py +++ b/backend/alembic/env.py @@ -1,8 +1,11 @@ from logging.config import fileConfig +from sqlalchemy import engine_from_config +from sqlalchemy import pool + +from database import DATABASE_URL + from alembic import context -from database import DATABASE_URL, Base -from sqlalchemy import engine_from_config, pool # this is the Alembic Config object, which provides # access to the values within the .ini file in use. @@ -18,6 +21,8 @@ if config.config_file_name is not None: # for 'autogenerate' support # from myapp import mymodel # target_metadata = mymodel.Base.metadata +from model import Base + target_metadata = Base.metadata # other values from the config, defined by the needs of env.py, diff --git a/backend/alembic/versions/9b1fabdaa344_init.py b/backend/alembic/versions/9b1fabdaa344_init.py new file mode 100644 index 0000000..465fc4d --- /dev/null +++ b/backend/alembic/versions/9b1fabdaa344_init.py @@ -0,0 +1,92 @@ +"""Init + +Revision ID: 9b1fabdaa344 +Revises: +Create Date: 2023-03-15 18:04:12.205139 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '9b1fabdaa344' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('courses', + sa.Column('name', sa.String(), nullable=True), + sa.Column('id', sa.String(), nullable=False), + sa.Column('semester', sa.String(), nullable=True), + sa.Column('responsible', sa.String(), nullable=True), + sa.Column('website', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('questions', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('question', sa.String(), nullable=True), + sa.Column('comment', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('users', + sa.Column('email', sa.String(), nullable=False), + sa.PrimaryKeyConstraint('email'), + sa.UniqueConstraint('email') + ) + op.create_table('course_question', + sa.Column('course_id', sa.String(), nullable=False), + sa.Column('question_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['course_id'], ['courses.id'], ), + sa.ForeignKeyConstraint(['question_id'], ['questions.id'], ), + sa.PrimaryKeyConstraint('course_id', 'question_id') + ) + op.create_table('enrollment', + sa.Column('user_email', sa.String(), nullable=False), + sa.Column('course_id', sa.String(), nullable=False), + sa.Column('role', sa.Enum('lecturer', 'teaching assistant', 'student', name='enrollment_roles'), nullable=False), + sa.ForeignKeyConstraint(['course_id'], ['courses.id'], ), + sa.ForeignKeyConstraint(['user_email'], ['users.email'], ), + sa.PrimaryKeyConstraint('user_email', 'course_id', 'role') + ) + op.create_table('units', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('seq_no', sa.Integer(), nullable=True), + sa.Column('title', sa.String(), nullable=True), + sa.Column('date_available', sa.Date(), nullable=True), + sa.Column('course_id', sa.String(), nullable=True), + sa.ForeignKeyConstraint(['course_id'], ['courses.id'], ), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('reflections', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('body', sa.String(), nullable=True), + sa.Column('timestamp', sa.Date(), nullable=True), + sa.Column('category', sa.String(), nullable=True), + sa.Column('is_interesting', sa.Boolean(), nullable=True), + sa.Column('is_problematic', sa.Boolean(), nullable=True), + sa.Column('is_sorted', sa.Boolean(), nullable=True), + sa.Column('user_id', sa.String(), nullable=True), + sa.Column('unit_id', sa.Integer(), nullable=True), + sa.Column('question_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['question_id'], ['questions.id'], ), + sa.ForeignKeyConstraint(['unit_id'], ['units.id'], ), + sa.ForeignKeyConstraint(['user_id'], ['users.email'], ), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('reflections') + op.drop_table('units') + op.drop_table('enrollment') + op.drop_table('course_question') + op.drop_table('users') + op.drop_table('questions') + op.drop_table('courses') + # ### end Alembic commands ### diff --git a/backend/alembic/versions/aa01c8290072_first_revision.py b/backend/alembic/versions/aa01c8290072_first_revision.py deleted file mode 100644 index f228de5..0000000 --- a/backend/alembic/versions/aa01c8290072_first_revision.py +++ /dev/null @@ -1,92 +0,0 @@ -"""First revision - -Revision ID: aa01c8290072 -Revises: -Create Date: 2023-03-10 14:33:14.535079 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'aa01c8290072' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('reflections') - op.drop_table('users') - op.drop_table('questions') - op.drop_table('course_question') - op.drop_table('units') - op.drop_table('enrollment') - op.drop_table('courses') - # ### end Alembic commands ### - - -def downgrade() -> None: - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('courses', - sa.Column('name', sa.VARCHAR(), nullable=True), - sa.Column('id', sa.VARCHAR(), nullable=False), - sa.Column('semester', sa.VARCHAR(), nullable=True), - sa.Column('responsible', sa.VARCHAR(), nullable=True), - sa.Column('website', sa.VARCHAR(), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('enrollment', - sa.Column('user_email', sa.VARCHAR(), nullable=False), - sa.Column('course_id', sa.VARCHAR(), nullable=False), - sa.Column('role', sa.VARCHAR(length=18), nullable=False), - sa.ForeignKeyConstraint(['course_id'], ['courses.id'], ), - sa.ForeignKeyConstraint(['user_email'], ['users.email'], ), - sa.PrimaryKeyConstraint('user_email', 'course_id', 'role') - ) - op.create_table('units', - sa.Column('id', sa.INTEGER(), nullable=False), - sa.Column('seq_no', sa.INTEGER(), nullable=True), - sa.Column('title', sa.VARCHAR(), nullable=True), - sa.Column('date_available', sa.DATE(), nullable=True), - sa.Column('course_id', sa.VARCHAR(), nullable=True), - sa.ForeignKeyConstraint(['course_id'], ['courses.id'], ), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('course_question', - sa.Column('course_id', sa.VARCHAR(), nullable=False), - sa.Column('question_id', sa.INTEGER(), nullable=False), - sa.ForeignKeyConstraint(['course_id'], ['courses.id'], ), - sa.ForeignKeyConstraint(['question_id'], ['questions.id'], ), - sa.PrimaryKeyConstraint('course_id', 'question_id') - ) - op.create_table('questions', - sa.Column('id', sa.INTEGER(), nullable=False), - sa.Column('question', sa.VARCHAR(), nullable=True), - sa.Column('comment', sa.VARCHAR(), nullable=True), - sa.PrimaryKeyConstraint('id') - ) - op.create_table('users', - sa.Column('email', sa.VARCHAR(), nullable=False), - sa.PrimaryKeyConstraint('email'), - sa.UniqueConstraint('email') - ) - op.create_table('reflections', - sa.Column('id', sa.INTEGER(), nullable=False), - sa.Column('body', sa.VARCHAR(), nullable=True), - sa.Column('timestamp', sa.DATE(), nullable=True), - sa.Column('category', sa.VARCHAR(), nullable=True), - sa.Column('is_interesting', sa.BOOLEAN(), nullable=True), - sa.Column('is_problematic', sa.BOOLEAN(), nullable=True), - sa.Column('is_sorted', sa.BOOLEAN(), nullable=True), - sa.Column('user_id', sa.VARCHAR(), nullable=True), - sa.Column('unit_id', sa.INTEGER(), nullable=True), - sa.Column('question_id', sa.INTEGER(), nullable=True), - sa.ForeignKeyConstraint(['question_id'], ['questions.id'], ), - sa.ForeignKeyConstraint(['unit_id'], ['units.id'], ), - sa.ForeignKeyConstraint(['user_id'], ['users.email'], ), - sa.PrimaryKeyConstraint('id') - ) - # ### end Alembic commands ### -- GitLab