add: App Firefly III

This commit is contained in:
Nicolas Meienberger 2022-07-26 16:30:47 +02:00
parent d5d1f95bfe
commit 5c674e9f84
12 changed files with 99 additions and 42 deletions

View File

@ -0,0 +1,28 @@
{
"name": "Firefly III",
"available": true,
"port": 8115,
"id": "firefly-iii",
"categories": ["finance"],
"description": "",
"short_desc": "Firefly III: a personal finances manager ",
"author": "JC5",
"website": "https://www.firefly-iii.org/",
"source": "https://github.com/firefly-iii/firefly-iii",
"image": "/logos/apps/firefly-iii.jpg",
"form_fields": [
{
"type": "email",
"label": "Your email",
"required": true,
"env_variable": "EMAIL"
},
{
"type": "random",
"min": 32,
"max": 32,
"label": "Random key",
"env_variable": "APP_KEY"
}
]
}

View File

@ -1,15 +1,16 @@
version: '3.9'
services:
fireflyiii:
firefly-iii:
image: fireflyiii/core:latest
container_name: firefly-iii
restart: unless-stopped
volumes:
- ${APP_DATA_DIR}/data/uplodad:/var/www/html/storage/upload
ports:
- ${APP_PORT}:8080
depends_on:
- fireflyiii-db
- firefly-iii-db
environment:
- APP_ENV=local
- APP_DEBUG=false
@ -20,11 +21,11 @@ services:
# Database
- DB_CONNECTION=mysql
- DB_HOST=fireflyiii-db
- DB_HOST=firefly-iii-db
- DB_PORT=3306
- DB_DATABASE=firefly
- DB_USERNAME=firefly
- DB_PASSWORD=${DB_PASSWORD}
- DB_PASSWORD=firefly
# Cookie settings
- COOKIE_PATH="/"
@ -32,26 +33,18 @@ services:
- COOKIE_SECURE=false
- COOKIE_SAMESITE=lax
# Firefly III can send you the following messages.
- SEND_REGISTRATION_MAIL=true
- SEND_ERROR_MESSAGE=true
- SEND_LOGIN_NEW_IP_WARNING=true
- APP_NAME=FireflyIII
- BROADCAST_DRIVER=log
- QUEUE_DRIVER=sync
- CACHE_PREFIX=firefly
- PUSHER_KEY=
- IPINFO_TOKEN=
- PUSHER_SECRET=
- PUSHER_ID=
- IS_HEROKU=false
- FIREFLY_III_LAYOUT=v1
- APP_URL=http://localhost:${APP_PORT}
networks:
- tipi_main_network
fireflyiii-db:
firefly-iii-db:
container_name: firefly-iii-db
image: mariadb
hostname: fireflyiii-db
restart: unless-stopped

View File

@ -0,0 +1,26 @@
"Firefly III" is a (self-hosted) manager for your personal finances. It can help you keep track of your expenses and income, so you can spend less and save more. Firefly III supports the use of budgets, categories and tags. Using a bunch of external tools, you can import data. It also has many neat financial reports available.
Firefly III should give you **insight** into and **control** over your finances. Money should be useful, not scary. You should be able to *see* where it is going, to *feel* your expenses and to... wow, I'm going overboard with this aren't I?
But you get the idea: this is your money. These are your expenses. Stop them from controlling you. I built this tool because I started to dislike money. Having money, not having money, paying bills with money, you get the idea. But no more. I want to feel "safe", whatever my balance is. And I hope this tool can help you. I know it helps me.
![Firefly III on iMac](https://raw.githubusercontent.com/firefly-iii/firefly-iii/develop/.github/assets/img/imac-complete.png)
### Purpose
Personal financial management is pretty difficult, and everybody has their own approach to it. Some people make budgets, other people limit their cashflow by throwing away their credit cards, others try to increase their current cashflow. There are tons of ways to save and earn money. Firefly III works on the principle that if you know where your money is going, you can stop it from going there.
By keeping track of your expenses and your income you can budget accordingly and save money. Stop living from paycheck to paycheck but give yourself the financial wiggle room you need.
You can read more about the purpose of Firefly III in the [documentation](https://docs.firefly-iii.org/).
![Firefly III on iPad](https://raw.githubusercontent.com/firefly-iii/firefly-iii/develop/.github/assets/img/ipad-complete.png)
## Need help?
If you need support using Firefly III or the associated tools, come find us!
- [GitHub Discussions for questions and support](https://github.com/firefly-iii/firefly-iii/discussions/)
- [Gitter.im for a good chat and a quick answer](https://gitter.im/firefly-iii/firefly-iii)
- [GitHub Issues for bugs and issues](https://github.com/firefly-iii/firefly-iii/issues)
- [Follow me around for news and updates on Twitter](https://twitter.com/Firefly_iii)

View File

@ -1,14 +0,0 @@
{
"name": "File Browser",
"available": true,
"port": 8096,
"id": "filebrowser",
"categories": ["utilities"],
"description": "Reliable and Performant File Management Desktop Sync and File Sharing\n Default credentials: admin / admin",
"short_desc": "Access your homeserver files from your browser",
"author": "filebrowser.org",
"website": "https://filebrowser.org/",
"source": "https://github.com/filebrowser/filebrowser",
"image": "/logos/apps/filebrowser.jpg",
"form_fields": []
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -13,4 +13,5 @@ export const APP_CATEGORIES = [
{ name: 'Books', id: AppCategoriesEnum.Books, icon: 'FaBook' },
{ name: 'Data', id: AppCategoriesEnum.Data, icon: 'FaDatabase' },
{ name: 'Music', id: AppCategoriesEnum.Music, icon: 'FaMusic' },
{ name: 'Finance', id: AppCategoriesEnum.Finance, icon: 'FaMoneyBillAlt' },
];

View File

@ -37,6 +37,7 @@ export enum AppCategoriesEnum {
Data = 'DATA',
Development = 'DEVELOPMENT',
Featured = 'FEATURED',
Finance = 'FINANCE',
Media = 'MEDIA',
Music = 'MUSIC',
Network = 'NETWORK',

View File

@ -38,4 +38,5 @@ export const colorSchemeForCategory: Record<AppCategoriesEnum, string> = {
[AppCategoriesEnum.Data]: 'red',
[AppCategoriesEnum.Books]: 'blue',
[AppCategoriesEnum.Music]: 'green',
[AppCategoriesEnum.Finance]: 'orange',
};

View File

@ -11,6 +11,9 @@ interface IProps {
initalValues?: Record<string, string>;
}
const hiddenTypes = ['random'];
const typeFilter = (field: FormField) => !hiddenTypes.includes(field.type);
const InstallForm: React.FC<IProps> = ({ formFields, onSubmit, initalValues }) => {
const renderField = (field: FormField) => {
return (
@ -30,7 +33,7 @@ const InstallForm: React.FC<IProps> = ({ formFields, onSubmit, initalValues }) =
validate={(values) => validateAppConfig(values, formFields)}
render={({ handleSubmit, validating, submitting }) => (
<form className="flex flex-col" onSubmit={handleSubmit}>
{formFields.map(renderField)}
{formFields.filter(typeFilter).map(renderField)}
<Button isLoading={validating || submitting} className="self-end mb-2" colorScheme="green" type="submit">
{initalValues ? 'Update' : 'Install'}
</Button>

View File

@ -1,6 +1,7 @@
import portUsed from 'tcp-port-used';
import { fileExists, readdirSync, readFile, readJsonFile, runScript, writeFile } from '../fs/fs.helpers';
import InternalIp from 'internal-ip';
import crypto from 'crypto';
import config from '../../config';
import { AppInfo } from './apps.types';
@ -84,6 +85,12 @@ export const ensureAppState = (appName: string, installed: boolean) => {
writeFile('/state/apps.json', JSON.stringify(state));
};
const getEntropy = (name: string, length: number) => {
const hash = crypto.createHash('sha256');
hash.update(name);
return hash.digest('hex').substring(0, length);
};
export const generateEnvFile = (appName: string, form: Record<string, string>) => {
const configFile: AppInfo = readJsonFile(`/apps/${appName}/config.json`);
const baseEnvFile = readFile('/.env').toString();
@ -91,10 +98,15 @@ export const generateEnvFile = (appName: string, form: Record<string, string>) =
configFile.form_fields?.forEach((field) => {
const formValue = form[field.env_variable];
const envVar = field.env_variable;
if (formValue) {
const envVar = field.env_variable;
envFile += `${envVar}=${formValue}\n`;
} else if (field.type === 'random') {
const length = field.min || 32;
const randomString = getEntropy(field.env_variable, length);
envFile += `${envVar}=${randomString}\n`;
} else if (field.required) {
throw new Error(`Variable ${field.env_variable} is required`);
}

View File

@ -14,6 +14,7 @@ export enum AppCategoriesEnum {
BOOKS = 'books',
DATA = 'data',
MUSIC = 'music',
FINANCE = 'finance',
}
export enum FieldTypes {
@ -25,6 +26,7 @@ export enum FieldTypes {
ip = 'ip',
fqdnip = 'fqdnip',
url = 'url',
random = 'random',
}
export enum AppStatusEnum {

View File

@ -15,20 +15,24 @@ import datasource from './config/datasource';
import appsService from './modules/apps/apps.service';
import { runUpdates } from './core/updates/run';
const corsOptions = {
credentials: true,
origin: function (origin: any, callback: any) {
// disallow requests with no origin
if (!origin) return callback(new Error('Not allowed by CORS'), false);
let corsOptions = {};
if (config.CLIENT_URLS.includes(origin)) {
return callback(null, true);
}
if (__prod__) {
corsOptions = {
credentials: true,
origin: function (origin: any, callback: any) {
// disallow requests with no origin
if (!origin) return callback(new Error('Not allowed by CORS'), false);
const message = "The CORS policy for this origin doesn't allow access from the particular origin.";
return callback(new Error(message), false);
},
};
if (config.CLIENT_URLS.includes(origin)) {
return callback(null, true);
}
const message = "The CORS policy for this origin doesn't allow access from the particular origin.";
return callback(new Error(message), false);
},
};
}
const main = async () => {
try {