소스 검색

Merge pull request #221 from meienberger/chore/cleanup

Chore/cleanup
Nicolas Meienberger 2 년 전
부모
커밋
3c10575b46

+ 9 - 17
Dockerfile

@@ -1,4 +1,4 @@
-FROM node:18-alpine3.16 AS build
+FROM node:18 AS build
 
 RUN npm install node-gyp -g
 
@@ -19,33 +19,25 @@ COPY ./packages/dashboard /dashboard
 RUN npm run build
 
 
-FROM node:18-alpine3.16 as app
+FROM alpine:3.16.0 as app
 
 WORKDIR /
 
-RUN apt-get update 
-# Install docker
-RUN apt-get install -y ca-certificates curl gnupg lsb-release jq
-RUN mkdir -p /etc/apt/keyrings
-RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
-RUN echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list >/dev/null
-RUN apt-get update
-RUN apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
+# # Install dependencies
+RUN apk --no-cache add nodejs npm
+RUN apk --no-cache add g++
+RUN apk --no-cache add make
+RUN apk --no-cache add python3
 
-# Install node
-RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash -
-RUN apt-get install -y nodejs
-
-# Install dependencies
 RUN npm install node-gyp -g
 
 WORKDIR /api
 COPY ./packages/system-api/package*.json /api/
-RUN npm install --production
+RUN npm install --omit=dev
 
 WORKDIR /dashboard
 COPY ./packages/dashboard/package*.json /dashboard/
-RUN npm install --production
+RUN npm install --omit=dev
 
 COPY --from=build /api/dist /api/dist
 COPY --from=build /dashboard/.next /dashboard/.next

+ 1 - 0
Dockerfile.dev

@@ -2,6 +2,7 @@ FROM node:18-alpine3.16
 
 WORKDIR /
 
+RUN apk --no-cache add g++ make
 RUN npm install node-gyp -g
 
 WORKDIR /api

+ 17 - 0
README.md

@@ -94,6 +94,21 @@ To stop Tipi, run the stop script.
 sudo ./scripts/stop.sh
 ```
 
+### Custom settings
+You can change the default settings by creating a `settings.json` file. The file should be located in the `state` directory. This file will make your changes persist across restarts. Example file:
+
+```json
+{
+  "dnsIp": "9.9.9.9", // DNS IP address
+  "domain": "mydomain.com", // Domain name to link to the dashboard
+  "port": 7000, // Change default http port 80
+  "sslPort": 7001, // Change default ssl port 443
+  "listenIp": "192.168.1.1", // Change default listen ip (advanced)
+  "storagePath": "/mnt/usb", // Change default storage path of app data
+}
+
+```
+
 ## Linking a domain to your dashboard
 If you want to link a domain to your dashboard, you can do so by providing the `--domain` option in the start script.
 
@@ -101,6 +116,8 @@ If you want to link a domain to your dashboard, you can do so by providing the `
 sudo ./scripts/start.sh --domain mydomain.com
 ```
 
+You can also specify it in the `settings.json` file as shown in the previous section.
+
 A Let's Encrypt certificate will be generated and installed automatically. Make sure to have ports 80 and 443 open on your firewall and that your domain has an **A** record pointing to your server IP.
 
 ## ❤️ Contributing

+ 2 - 2
package.json

@@ -1,13 +1,13 @@
 {
   "name": "runtipi",
-  "version": "0.6.1",
+  "version": "0.6.2",
   "description": "A homeserver for everyone",
   "scripts": {
     "prepare": "husky install",
     "commit": "git-cz",
     "act:test-install": "act --container-architecture linux/amd64 -j test-install",
     "act:docker": "act --container-architecture linux/amd64 --secret-file github.secrets -j build-images",
-    "start:dev": "./scripts/start-dev.sh",
+    "start:dev": "sudo ./scripts/start-dev.sh",
     "start:rc": "docker-compose -f docker-compose.rc.yml --env-file .env up --build",
     "start:prod": "docker-compose --env-file .env up --build",
     "start:pg": "docker run --name test-db -p 5433:5432 -d --rm -e POSTGRES_PASSWORD=postgres postgres",

+ 1 - 5
packages/dashboard/package.json

@@ -1,6 +1,6 @@
 {
   "name": "dashboard",
-  "version": "0.6.1",
+  "version": "0.6.2",
   "private": true,
   "scripts": {
     "test": "jest --colors",
@@ -17,14 +17,11 @@
     "@emotion/react": "^11",
     "@emotion/styled": "^11",
     "@fontsource/open-sans": "^4.5.8",
-    "axios": "^0.26.1",
     "clsx": "^1.1.1",
     "final-form": "^4.20.6",
     "framer-motion": "^6",
     "graphql": "^15.8.0",
     "graphql-tag": "^2.12.6",
-    "immer": "^9.0.12",
-    "js-cookie": "^3.0.1",
     "next": "12.1.6",
     "react": "18.1.0",
     "react-dom": "18.1.0",
@@ -36,7 +33,6 @@
     "remark-gfm": "^3.0.1",
     "remark-mdx": "^2.1.1",
     "swr": "^1.3.0",
-    "systeminformation": "^5.11.9",
     "tslib": "^2.4.0",
     "validator": "^13.7.0",
     "zustand": "^3.7.2"

+ 8 - 0
packages/dashboard/src/components/Layout/SideMenu.tsx

@@ -10,6 +10,7 @@ import { useRouter } from 'next/router';
 import { IconType } from 'react-icons';
 import { useLogoutMutation, useVersionQuery } from '../../generated/graphql';
 import { getUrl } from '../../core/helpers/url-helpers';
+import { BsHeart } from 'react-icons/bs';
 
 const SideMenu: React.FC = () => {
   const router = useRouter();
@@ -57,6 +58,12 @@ const SideMenu: React.FC = () => {
       <Flex flex="1" />
       <List>
         <div className="mx-3">
+          <a href="https://github.com/meienberger/runtipi?sponsor=1" target="_blank" rel="noreferrer">
+            <ListItem className="cursor-pointer hover:font-bold flex items-center mb-4">
+              <BsHeart size={20} className="mr-3" />
+              <p className="flex-1 mb-1 text-md">Donate</p>
+            </ListItem>
+          </a>
           <ListItem onClick={() => logout()} className="cursor-pointer hover:font-bold flex items-center mb-5">
             <FiLogOut size={20} className="mr-3" />
             <p className="flex-1">Log out</p>
@@ -68,6 +75,7 @@ const SideMenu: React.FC = () => {
           </ListItem>
         </div>
       </List>
+
       <div className="pb-1 text-center text-sm text-gray-400 mt-5">Tipi version {Package.version}</div>
       {!isLatest && (
         <Badge className="self-center mt-1" colorScheme="green">

+ 0 - 34
packages/dashboard/src/core/api.ts

@@ -1,34 +0,0 @@
-import axios, { Method } from 'axios';
-import { useSystemStore } from '../state/systemStore';
-
-interface IFetchParams {
-  endpoint: string;
-  method?: Method;
-  params?: JSON;
-  data?: Record<string, unknown>;
-}
-
-const api = async <T = unknown>(fetchParams: IFetchParams): Promise<T> => {
-  const { endpoint, method = 'GET', params, data } = fetchParams;
-
-  const { getState } = useSystemStore;
-  const BASE_URL = getState().baseUrl;
-
-  const response = await axios.request<T & { error?: string }>({
-    method,
-    params,
-    data,
-    url: `${BASE_URL}${endpoint}`,
-    withCredentials: true,
-  });
-
-  if (response.data.error) {
-    throw new Error(response.data.error);
-  }
-
-  if (response.data) return response.data;
-
-  throw new Error(`Network request error. status : ${response.status}`);
-};
-
-export default { fetch: api };

+ 0 - 11
packages/dashboard/src/core/fetcher.ts

@@ -1,11 +0,0 @@
-import { BareFetcher } from 'swr';
-import axios from 'axios';
-import { useSystemStore } from '../state/systemStore';
-
-const fetcher: BareFetcher<any> = (url: string) => {
-  const { baseUrl } = useSystemStore.getState();
-
-  return axios.get(url, { baseURL: baseUrl, withCredentials: true }).then((res) => res.data);
-};
-
-export default fetcher;

+ 0 - 74
packages/dashboard/src/state/authStore.ts

@@ -1,74 +0,0 @@
-import create from 'zustand';
-import Cookies from 'js-cookie';
-import api from '../core/api';
-import { IUser } from '../core/types';
-
-type AppsStore = {
-  user: IUser | null;
-  configured: boolean;
-  me: () => Promise<void>;
-  login: (email: string, password: string) => Promise<void>;
-  register: (email: string, password: string) => Promise<void>;
-  logout: () => void;
-  fetchConfigured: () => Promise<void>;
-  loading: boolean;
-};
-
-export const useAuthStore = create<AppsStore>((set) => ({
-  user: null,
-  configured: false,
-  loading: false,
-  me: async () => {
-    try {
-      set({ loading: true });
-      const response = await api.fetch<{ user: IUser | null }>({ endpoint: '/auth/me' });
-
-      set({ user: response.user, loading: false });
-    } catch (error) {
-      set({ loading: false, user: null });
-    }
-  },
-  login: async (email: string, password: string) => {
-    set({ loading: true });
-
-    try {
-      const response = await api.fetch<{ user: IUser }>({
-        endpoint: '/auth/login',
-        method: 'post',
-        data: { email, password },
-      });
-      set({ user: response.user, loading: false });
-    } catch (e) {
-      set({ loading: false });
-      throw e;
-    }
-  },
-  logout: async () => {
-    Cookies.remove('tipi_token');
-
-    set({ user: null, loading: false });
-  },
-  register: async (email: string, password: string) => {
-    set({ loading: true });
-
-    try {
-      const response = await api.fetch<{ user: IUser }>({
-        endpoint: '/auth/register',
-        method: 'post',
-        data: { email, password },
-      });
-      set({ user: response.user, loading: false });
-    } catch (e) {
-      set({ loading: false });
-      throw e;
-    }
-  },
-  fetchConfigured: async () => {
-    try {
-      const response = await api.fetch<{ configured: boolean }>({ endpoint: '/auth/configured' });
-      set({ configured: response.configured });
-    } catch (e) {
-      set({ configured: false });
-    }
-  },
-}));

+ 1 - 12
packages/system-api/package.json

@@ -1,6 +1,6 @@
 {
   "name": "system-api",
-  "version": "0.6.1",
+  "version": "0.6.2",
   "description": "",
   "exports": "./dist/server.js",
   "type": "module",
@@ -30,8 +30,6 @@
     "argon2": "^0.29.1",
     "axios": "^0.26.1",
     "class-validator": "^0.13.2",
-    "compression": "^1.7.4",
-    "cookie-parser": "^1.4.6",
     "cors": "^2.8.5",
     "dotenv": "^16.0.0",
     "express": "^4.17.3",
@@ -41,18 +39,13 @@
     "graphql-type-json": "^0.3.2",
     "http": "0.0.1-security",
     "internal-ip": "^6.0.0",
-    "jsonwebtoken": "^8.5.1",
-    "mock-fs": "^5.1.2",
     "node-cache": "^5.1.2",
     "node-cron": "^3.0.1",
     "node-port-scanner": "^3.0.1",
-    "p-iteration": "^1.1.8",
     "pg": "^8.7.3",
-    "public-ip": "^5.0.0",
     "reflect-metadata": "^0.1.13",
     "semver": "^7.3.7",
     "session-file-store": "^1.5.0",
-    "systeminformation": "^5.11.9",
     "tcp-port-used": "^1.0.2",
     "type-graphql": "^1.1.1",
     "typeorm": "^0.3.6",
@@ -64,15 +57,11 @@
     "@faker-js/faker": "^7.3.0",
     "@swc/cli": "^0.1.57",
     "@swc/core": "^1.2.210",
-    "@types/compression": "^1.7.2",
-    "@types/cookie-parser": "^1.4.3",
     "@types/cors": "^2.8.12",
     "@types/express": "^4.17.13",
     "@types/express-session": "^1.17.4",
     "@types/fs-extra": "^9.0.13",
     "@types/jest": "^27.5.0",
-    "@types/jsonwebtoken": "^8.5.8",
-    "@types/mock-fs": "^4.13.1",
     "@types/node": "17.0.31",
     "@types/node-cron": "^3.0.2",
     "@types/pg": "^8.6.5",

+ 11 - 5
packages/system-api/src/core/config/EventDispatcher.ts

@@ -69,7 +69,7 @@ class EventDispatcher {
       return;
     }
 
-    this.clearEvent(this.lock.id);
+    this.clearEvent(this.lock, status);
     this.lock = null;
   }
 
@@ -165,10 +165,16 @@ class EventDispatcher {
    * Clear event from queue
    * @param id - Event id
    */
-  private clearEvent(id: string) {
-    this.queue = this.queue.filter((e) => e.id !== id);
-    if (fs.existsSync(`/app/logs/${id}.log`)) {
-      fs.unlinkSync(`/app/logs/${id}.log`);
+  private clearEvent(event: SystemEvent, status: EventStatusTypes = 'success') {
+    this.queue = this.queue.filter((e) => e.id !== event.id);
+    if (fs.existsSync(`/app/logs/${event.id}.log`)) {
+      const log = fs.readFileSync(`/app/logs/${event.id}.log`, 'utf8');
+      if (log && status === 'error') {
+        logger.error(`EventDispatcher: ${event.type} ${event.id} failed with error: ${log}`);
+      } else if (log) {
+        logger.info(`EventDispatcher: ${event.type} ${event.id} finished with message: ${log}`);
+      }
+      fs.unlinkSync(`/app/logs/${event.id}.log`);
     }
     fs.writeFileSync(WATCH_FILE, '');
   }

+ 3 - 2
packages/system-api/src/core/config/__tests__/EventDispatcher.test.ts

@@ -154,10 +154,11 @@ describe('EventDispatcher - getEventStatus', () => {
 
 describe('EventDispatcher - clearEvent', () => {
   it('Should clear event', async () => {
+    const event = { id: '123', type: EventTypes.APP, args: [], creationDate: new Date() };
     // @ts-ignore
-    eventDispatcher.queue = [{ id: '123', type: EventTypes.APP, args: [], creationDate: new Date() }];
+    eventDispatcher.queue = [event];
     // @ts-ignore
-    eventDispatcher.clearEvent('123');
+    eventDispatcher.clearEvent(event);
 
     // @ts-ignore
     const queue = eventDispatcher.queue;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 12 - 266
pnpm-lock.yaml


+ 2 - 0
scripts/git.sh

@@ -46,6 +46,7 @@ if [[ "$command" = "update" ]]; then
     repo="$2"
     repo_hash=$(get_hash "${repo}")
     repo_dir="${ROOT_FOLDER}/repos/${repo_hash}"
+    git config --global --add safe.directory "${repo_dir}"
     if [ ! -d "${repo_dir}" ]; then
         write_log "Repo does not exist"
         exit 1
@@ -55,6 +56,7 @@ if [[ "$command" = "update" ]]; then
     cd "${repo_dir}" || exit
 
     if ! git pull origin master; then
+        cd "${ROOT_FOLDER}" || exit
         write_log "Failed to update repo"
         exit 1
     fi

+ 2 - 0
scripts/start-dev.sh

@@ -5,5 +5,7 @@ ROOT_FOLDER="${PWD}"
 
 kill_watcher
 "${ROOT_FOLDER}/scripts/watcher.sh" &
+chmod -R a+rwx "${ROOT_FOLDER}/state/events"
+chmod -R a+rwx "${ROOT_FOLDER}/state/system-info.json"
 
 docker compose -f docker-compose.dev.yml --env-file "${ROOT_FOLDER}/.env.dev" up --build

+ 3 - 0
scripts/start.sh

@@ -201,6 +201,9 @@ mv -f "$ENV_FILE" "$ROOT_FOLDER/.env"
 # Run system-info.sh
 echo "Running system-info.sh..."
 bash "${ROOT_FOLDER}/scripts/system-info.sh"
+echo "Fixing permissions for events file"
+chmod -R a+rwx "${ROOT_FOLDER}/state/events"
+chmod -R a+rwx "${ROOT_FOLDER}/state/system-info.json"
 
 ## Don't run if config-only
 if [[ ! $ci == "true" ]]; then

+ 4 - 0
scripts/system-info.sh

@@ -1,8 +1,12 @@
 #!/usr/bin/env bash
 set -e # Exit immediately if a command exits with a non-zero status.
 
+ROOT_FOLDER="${PWD}"
+STATE_FOLDER="${ROOT_FOLDER}/state"
+
 # if not on linux exit
 if [[ "$(uname)" != "Linux" ]]; then
+    echo '{"cpu": { "load": 0 },"memory": { "available": 0, "total": 0, "used": 0 },"disk": { "available": 0, "total": 0, "used": 0 }}' >"${STATE_FOLDER}/system-info.json"
     exit 0
 fi
 

+ 3 - 1
scripts/system.sh

@@ -1,9 +1,10 @@
 #!/usr/bin/env bash
 
 source "${BASH_SOURCE%/*}/common.sh"
-
 ensure_pwd
 
+ROOT_FOLDER="${PWD}"
+
 if [ -z ${1+x} ]; then
     command=""
 else
@@ -23,6 +24,7 @@ fi
 # Update Tipi
 if [[ "$command" = "update" ]]; then
     scripts/stop.sh
+    git config --global --add safe.directory "${ROOT_FOLDER}"
     git pull origin master
     scripts/start.sh
     exit

+ 0 - 1
scripts/watcher.sh

@@ -97,7 +97,6 @@ function select_command() {
     return 0
 }
 
-check_running
 write_log "Listening for events in ${WATCH_FILE}..."
 clean_events
 # Listen in for changes in the WATCH_FILE

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.