diff --git a/README.md b/README.md index 7f91e3e..854b54b 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,16 @@ # toolshed -## Development +## Installation / Development ``` bash git clone https://github.com/gr4yj3d1/toolshed.git ``` - or - ``` bash git clone https://git.neulandlabor.de/j3d1/toolshed.git ``` -all following development mode commands support auto-reloading and hot-reloading where applicable, they do not need to bw -restarted after changes. - -### Backend only +### Backend ``` bash cd toolshed/backend @@ -25,11 +20,9 @@ pip install -r requirements.txt python configure.py python manage.py runserver 0.0.0.0:8000 --insecure ``` +to run this in properly in production, you need to configure a webserver to serve the static files and proxy the requests to the backend, then run the backend with just `python manage.py runserver` without the `--insecure` flag. -to run this in properly in production, you need to configure a webserver to serve the static files and proxy the -requests to the backend, then run the backend with just `python manage.py runserver` without the `--insecure` flag. - -### Frontend only +### Frontend ``` bash cd toolshed/frontend @@ -37,44 +30,14 @@ npm install npm run dev ``` -### Docs only +### Docs ``` bash cd toolshed/docs mkdocs serve ``` -### Full stack -``` bash -cd toolshed -docker-compose -f deploy/docker-compose.override.yml up --build -``` - -## Deployment - -### Requirements - -- python3 -- python3-pip -- python3-venv -- wget -- unzip -- nginx -- uwsgi - -### Installation - -* Get the latest release from -`https://git.neulandlabor.de/j3d1/toolshed/releases/download//toolshed.zip` or -`https://github.com/gr4yj3d1/toolshed/archive/refs/tags/.zip`. -* Unpack it to `/var/www` or wherever you want to install toolshed. -* Create a virtual environment and install the requirements. -* Then run the configuration script. -* Configure your webserver to serve the static files and proxy the requests to the backend. -* Configure your webserver to run the backend with uwsgi. - -for detailed instructions see [docs](/docs/deployment.md). ## CLI Client diff --git a/backend/configure.py b/backend/configure.py index e027805..ee26cac 100755 --- a/backend/configure.py +++ b/backend/configure.py @@ -8,41 +8,32 @@ import dotenv from django.db import transaction, IntegrityError -class CmdCtx: +def yesno(prompt, default=False): + if not sys.stdin.isatty(): + return default + yes = {'yes', 'y', 'ye'} + no = {'no', 'n'} - def __init__(self, args): - self.args = args + if default: + yes.add('') + else: + no.add('') - def yesno(self, prompt, default=False): - if not sys.stdin.isatty() or self.args.noninteractive: - return default - elif self.args.yes: + hint = ' [Y/n] ' if default else ' [y/N] ' + + while True: + choice = input(prompt + hint).lower() + if choice in yes: return True - elif self.args.no: + elif choice in no: return False - yes = {'yes', 'y', 'ye'} - no = {'no', 'n'} - - if default: - yes.add('') else: - no.add('') - - hint = ' [Y/n] ' if default else ' [y/N] ' - - while True: - choice = input(prompt + hint).lower() - if choice in yes: - return True - elif choice in no: - return False - else: - print('Please respond with "yes" or "no"') + print('Please respond with "yes" or "no"') -def configure(ctx): +def configure(): if not os.path.exists('.env'): - if not ctx.yesno("the .env file does not exist, do you want to create it?", default=True): + if not yesno("the .env file does not exist, do you want to create it?", default=True): print('Aborting') exit(0) if not os.path.exists('.env.dist'): @@ -65,7 +56,7 @@ def configure(ctx): current_hosts = os.getenv('ALLOWED_HOSTS') print('Current ALLOWED_HOSTS: {}'.format(current_hosts)) - if ctx.yesno("Do you want to add ALLOWED_HOSTS?"): + if yesno("Do you want to add ALLOWED_HOSTS?"): hosts = input("Enter a comma-separated list of allowed hosts: ") joined_hosts = current_hosts + ',' + hosts if current_hosts else hosts dotenv.set_key('.env', 'ALLOWED_HOSTS', joined_hosts) @@ -76,21 +67,20 @@ def configure(ctx): django.setup() if not os.path.exists('db.sqlite3'): - if not ctx.yesno("No database found, do you want to create one?", default=True): + if not yesno("No database found, do you want to create one?", default=True): print('Aborting') exit(0) from django.core.management import call_command call_command('migrate') - if ctx.yesno("Do you want to create a superuser?"): + if yesno("Do you want to create a superuser?"): from django.core.management import call_command call_command('createsuperuser') call_command('collectstatic', '--no-input') - if ctx.yesno("Do you want to import all categories, properties and tags contained in this repository?", - default=True): + if yesno("Do you want to import all categories, properties and tags contained in this repository?", default=True): from hostadmin.serializers import CategorySerializer, PropertySerializer, TagSerializer from hostadmin.models import ImportedIdentifierSets from hashlib import sha256 @@ -206,7 +196,6 @@ def main(): parser = ArgumentParser(description='Toolshed Server Configuration') parser.add_argument('--yes', '-y', help='Answer yes to all questions', action='store_true') parser.add_argument('--no', '-n', help='Answer no to all questions', action='store_true') - parser.add_argument('--noninteractive', '-x', help="Run in noninteractive mode", action='store_true') parser.add_argument('cmd', help='Command', default='configure', nargs='?') args = parser.parse_args() @@ -214,10 +203,8 @@ def main(): print('Error: --yes and --no are mutually exclusive') exit(1) - ctx = CmdCtx(args) - if args.cmd == 'configure': - configure(ctx) + configure() elif args.cmd == 'reset': reset() elif args.cmd == 'testdata': diff --git a/deploy/docker-compose.prod.yml b/deploy/docker-compose.prod.yml new file mode 100644 index 0000000..9b6be6c --- /dev/null +++ b/deploy/docker-compose.prod.yml @@ -0,0 +1,54 @@ +version: '3.8' + +services: + backend: + build: + context: ../backend/ + dockerfile: ../deploy/dev/Dockerfile.backend + volumes: + - ../backend:/code + expose: + - 8000 + command: bash -c "python configure.py; python configure.py testdata; python manage.py runserver 0.0.0.0:8000 --insecure" + + frontend: + build: + context: ../frontend/ + dockerfile: ../deploy/dev/Dockerfile.frontend + volumes: + - ../frontend:/app + expose: + - 5173 + command: npm run dev -- --host + + wiki: + build: + context: ../ + dockerfile: deploy/dev/Dockerfile.wiki + volumes: + - ../mkdocs.yml:/wiki/mkdocs.yml + - ../docs:/wiki/docs + expose: + - 8001 + command: mkdocs serve --dev-addr=0.0.0.0:8001 + + nginx: + image: nginx:latest + volumes: + - ./dev/fullchain.pem2:/etc/nginx/nginx.crt + - ./dev/privkey.pem2:/etc/nginx/nginx.key + - ./dev/nginx-instance_a.dev.conf:/etc/nginx/nginx.conf + - ./dev/dns.json:/var/www/dns.json + - ./dev/domains.json:/var/www/domains.json + ports: + - 8080:8080 + - 5353:5353 + + dns: + build: + context: ./dev/ + dockerfile: Dockerfile.dns + volumes: + - ./dev/zone.json:/dns/zone.json + expose: + - 8053 \ No newline at end of file diff --git a/deploy/prod/Dockerfile.frontend b/deploy/prod/Dockerfile.frontend new file mode 100644 index 0000000..10a2cc3 --- /dev/null +++ b/deploy/prod/Dockerfile.frontend @@ -0,0 +1,15 @@ +# Use an official Node.js runtime as instance_a parent image +FROM node:14 + +# Set work directory +WORKDIR /app + +# Install app dependencies +# A wildcard is used to ensure both package.json AND package-lock.json are copied +COPY package.json ./ + +RUN npm install +# If you are building your code for production +# RUN npm ci --only=production + +CMD [ "npm", "run", "dev", "--", "--host"] diff --git a/deploy/prod/Dockerfile.frontend.prod b/deploy/prod/Dockerfile.frontend.prod new file mode 100644 index 0000000..7b3947e --- /dev/null +++ b/deploy/prod/Dockerfile.frontend.prod @@ -0,0 +1,14 @@ +ROM node:alpine as builder +WORKDIR /app +COPY ./package.json /app/package.json +COPY . /app +RUN npm ci --only=production +RUN npm run build + + +FROM nginx:alpine as runner +#RUN apk add --update npm +WORKDIR /app +COPY --from=builder /app/dist /usr/share/nginx/html +COPY ./nginx.conf /etc/nginx/nginx.conf +EXPOSE 80 diff --git a/docs/deployment.md b/docs/deployment.md deleted file mode 100644 index 9262ebe..0000000 --- a/docs/deployment.md +++ /dev/null @@ -1,102 +0,0 @@ -# Deployment - -## Native - -### Requirements - -- python3 -- python3-pip -- python3-venv -- wget -- unzip -- nginx -- uwsgi -- certbot - -### Installation - -Get the latest release: - -``` bash -cd /var/www # or wherever you want to install toolshed -wget https://git.neulandlabor.de/j3d1/toolshed/releases/download//toolshed.zip -``` -or from github: -``` bash -cd /var/www # or wherever you want to install toolshed -wget https://github.com/gr4yj3d1/toolshed/archive/refs/tags/.zip -O toolshed.zip -``` - -Extract and configure the backend: - -``` bash -unzip toolshed.zip -cd toolshed/backend -python3 -m venv venv -source venv/bin/activate -pip install -r requirements.txt -python configure.py -``` - -Configure uWSGI to serve the backend locally: - -``` bash -cd /var/www/toolshed/backend -cp toolshed.ini /etc/uwsgi/apps-available/ -ln -s /etc/uwsgi/apps-available/toolshed.ini /etc/uwsgi/apps-enabled/ -systemctl restart uwsgi -``` - -Configure nginx to serve the static files and proxy the requests to the backend: - -``` bash -cd /var/www/toolshed/backend -cp toolshed.nginx /etc/nginx/sites-available/toolshed -ln -s /etc/nginx/sites-available/toolsheed /etc/nginx/sites-enabled/ -systemctl restart nginx -``` - -Configure certbot to get a certificate for the domain: - -``` bash -certbot --nginx -d -``` - -### Update - -``` bash -cd /var/www -wget https://git.neulandlabor.de/j3d1/toolshed/releases/download//toolshed.zip -unzip toolshed.zip -cd toolshed/backend -source venv/bin/activate -pip install -r requirements.txt -python configure.py -systemctl restart uwsgi -``` - -## Docker - -### Requirements - -- docker -- docker-compose -- git - -### Installation - -``` bash -git clone https://git.neulandlabor.de/j3d1/toolshed.git -# or -git clone https://github.com/gr4yj3d1/toolshed.git -cd toolshed -docker-compose -f deploy/docker-compose.prod.yml up -d --build -``` - -### Update - -``` bash -toolshed -git pull -docker-compose -f deploy/docker-compose.prod.yml up -d --build -``` \ No newline at end of file diff --git a/docs/development.md b/docs/development.md deleted file mode 100644 index 3fcd229..0000000 --- a/docs/development.md +++ /dev/null @@ -1,105 +0,0 @@ -# Development - -``` bash -git clone https://github.com/gr4yj3d1/toolshed.git -``` - -or - -``` bash -git clone https://git.neulandlabor.de/j3d1/toolshed.git -``` - -## Native - -To a certain extent, the frontend and backend can be developed independently. The frontend is a Vue.js project and the -backend is a DRF (Django-Rest-Framework) project. If you want to develop the frontend, you can do so without the backend -and vice -versa. However, especially for the frontend, it is recommended to use the backend as well, as the frontend does not have -a lot of 'offline' functionality. -If you want to run the fullstack application, it is recommended to use the [docker-compose](#docker) method. - -### Frontend - -install `node.js` and `npm` - -on Debian* for example: `sudo apt install npm` - -``` bash -cd toolshed/frontend -npm install -npm run dev -``` - -### Backend - -Install `python3`, `pip` and `virtualenv` - -on Debian* for example: `sudo apt install python3 python3-pip python3-venv` - -Prepare backend environment - -``` bash -cd toolshed/backend -python -m venv venv -source venv/bin/activate -pip install -r requirements.txt -``` - -Run the test suite: - -``` bash -python manage.py test -``` - -optionally with coverage: - -``` bash -coverage run manage.py test -coverage report -``` - -Start the backend in development mode: - -``` bash -python manage.py migrate -cp .env.dist .env -echo "DEBUG = True" >> .env -python manage.py runserver 0.0.0.0:8000 -``` - -provides the api docs at `http://localhost:8000/docs/` - -### Docs (Wiki) - -Install `mkdocs` - -on Debian* for example: `sudo apt install mkdocs` - -Start the docs server: - -``` bash -cd toolshed/docs -mkdocs serve -a 0.0.0.0:8080 -``` - -## Docker - -### Fullstack - -Install `docker` and `docker-compose` - -on Debian* for example: `sudo apt install docker.io docker-compose` - -Start the fullstack application: - -``` bash -docker-compose -f deploy/docker-compose.override.yml up --build -``` - -This will start an instance of the frontend and wiki, a limited DoH (DNS over HTTPS) server and **two** instances of the backend. -The two backend instances are set up to use the domains `a.localhost` and `b.localhost`, the local DoH -server is used to direct the frontend to the correct backend instance. -The frontend is configured to act as if it was served from the domain `a.localhost`. -Access the frontend at `http://localhost:8080/`, backend at `http://localhost:8080/api/`, api docs -at `http://localhost:8080/docs/` and the wiki at `http://localhost:8080/wiki/`. \ No newline at end of file diff --git a/docs/federation.md b/docs/federation.md deleted file mode 100644 index d242677..0000000 --- a/docs/federation.md +++ /dev/null @@ -1,23 +0,0 @@ -# Federation - -This section will cover how federation works in Toolshed. - -## What is Federation? - -Since user of Toolshed you can search and interact the inventory of all their 'friends' that are potentially on -different servers there is a need for a way to communicate between servers. We don't want to rely on a central server that -stores all the data and we don't want to have a central server that handles all the communication between servers. This -is where federation comes in. Toolshed uses a protocol that can not only exchange data with the server where the user -is registered but also with the servers where their friends are registered. - -## How does it work? - -Any user can register on any server and creates a personal key pair. The public key is stored on the server and the private -key is stored on the client. The private key is used to sign all requests to the server and the public key is used to -verify the signature. Once a user has registered on a server they can send friend requests to other users containing -their public key. If the other user accepts the friend request, the server stores the public key of the friend and -uses it to verify access to the friend's inventory. While accepting a friend request the user also automatically sends -their own public key to the friend's server. This way both users can access each other's inventory. - -The protocol is based on a simple HTTPS API exchanging JSON data that is signed with the user's private key. By default -Toolshed servers provide a documentation of the API at [/docs/api](/docs/api). \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 95588dd..0ba4a97 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,8 +6,47 @@ This is the documentation for the Toolshed project. It is a work in progress. `#social` `#network` `#federation` `#decentralized` `#federated` `#socialnetwork` `#fediverse` `#community` `#hashtags` ## Getting Started - - [Deploying Toolshed](deployment.md) - - [Development Setup](development.md) - - [About Federation](federation.md) +## Installation +``` bash + # TODO add installation instructions + # similar to development instructions just with more docker + # TODO add docker-compose.yml +``` + +## Development + +``` bash +git clone https://github.com/gr4yj3d1/toolshed.git +``` +or +``` bash +git clone https://git.neulandlabor.de/j3d1/toolshed.git +``` + +### Frontend + +``` bash +cd toolshed/frontend +npm install +npm run dev +``` + +### Backend + +``` bash +cd toolshed/backend +python3 -m venv venv +source venv/bin/activate +pip install -r requirements.txt +python manage.py migrate +python manage.py runserver 0.0.0.0:8000 +``` + +### Docs + +``` bash +cd toolshed/docs +mkdocs serve -a 0.0.0.0:8080 +``` diff --git a/frontend/src/components/BaseLayout.vue b/frontend/src/components/BaseLayout.vue index 21b3d75..75a836a 100644 --- a/frontend/src/components/BaseLayout.vue +++ b/frontend/src/components/BaseLayout.vue @@ -1,6 +1,5 @@