diff --git a/Dockerfile b/Dockerfile index a6776c5..249acc0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,11 +5,15 @@ WORKDIR /app COPY . . -RUN apk add build-base libffi-dev +RUN apk add build-base libffi-dev shadow + +RUN \ + addgroup -g 911 abc && \ + adduser -D -H -u 911 -G abc abc && \ + usermod -G users abc RUN \ cd /app && \ - pip install gunicorn && \ pip install -r requirements.txt && \ chmod +x run.sh && \ chmod +x verify_env.py && \ @@ -17,9 +21,10 @@ RUN \ RUN \ cd /app/client && \ - npm install node-sass && \ npm ci && \ + npm install node-sass && \ npm run build +USER abc EXPOSE 5000 ENTRYPOINT "./run.sh" \ No newline at end of file diff --git a/README.md b/README.md index 28eaacb..d6006ba 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

-Current version: **1.0-beta10** +Current version: **1.0-beta11** ## About The idea for this app came from using my Hobonichi Techo planner every morning to write down what I needed to accomplish that day & using it for scratching down random thoughts and notes as the day went on. The closest thing I've seen to an app for replacing this system is Noteplan, but I don't use a Mac or an iOS device, and it's not self-hostable, so I decided to write my own. @@ -17,7 +17,7 @@ Since I had the need for keeping track of to-dos throughout the day, regular Mar ## Roadmap I'd like to try add include at least of some the following features to get to a final v1.0 release: - - CalDAV support + - iCal support - HTML preview (instead of just markdown) - Kanban board for tasks (and new syntax to attach meta info like swimlane and project for each task) - Nested tagging @@ -50,7 +50,10 @@ The recommended way of running is to pull the image from [Docker Hub](https://hu | API_SECRET_KEY | Used to sign API tokens. | Will be generated automatically if not passed in. | | DATABASE_URI | Connection string for DB. | Will create and use a SQLite DB if not passed in. | | DB_ENCRYPTION_KEY | Secret key for encrypting data. Length must be a multiple of 16.

*Warning*: If changed data will not be able to be decrypted! | Will be generated automatically if not passed in. | -| PREVENT_SIGNUPS | Disable signup form? Anything in this variable will prevent signups. | | +| PREVENT_SIGNUPS | Disable signup form? Anything in this variable will prevent signups. | False | +| BASE_URL | Used when using a subfolder on a reverse proxy | None | +| PUID | User ID (for folder permissions) | None | +| PGID | Group ID (for folder permissions) | None | #### Volumes diff --git a/app/models.py b/app/models.py index fb22b01..e373b47 100644 --- a/app/models.py +++ b/app/models.py @@ -51,6 +51,7 @@ class User(db.Model): uuid = db.Column(GUID, primary_key=True, index=True, unique=True, default=lambda: uuid.uuid4()) username = db.Column(db.String(64), unique=True, nullable=False) password_hash = db.Column(db.String(128), nullable=False) + auto_save = db.Column(db.Boolean, nullable=True) notes = db.relationship('Note', lazy='dynamic', cascade='all, delete, delete-orphan') meta = db.relationship('Meta', lazy='dynamic', cascade='all, delete, delete-orphan') diff --git a/app/routes.py b/app/routes.py index 50c426c..04c8d28 100644 --- a/app/routes.py +++ b/app/routes.py @@ -306,8 +306,34 @@ def sidebar_data(): tags = sorted(set([a.name for a in user.meta.filter_by(kind="tag").all()]), key=lambda s: s.lower()) projects = sorted(set([a.name for a in user.meta.filter_by(kind="project").all()]), key=lambda s: s.lower()) tasks = sorted([a.serialize for a in user.meta.filter_by(kind="task").all()], key=lambda task: task['note_id']) + auto_save = user.auto_save - return jsonify(tags=tags,projects=projects,notes=notes,tasks=tasks), 200 + return jsonify(tags=tags,projects=projects,notes=notes,tasks=tasks,auto_save=auto_save), 200 + + +@app.route('/api/toggle_auto_save', methods=['POST']) +@jwt_required() +def toggle_auto_save(): + req = request.get_json() + auto_save = req.get('auto_save', False) + + username = get_jwt_identity() + + if not username: + abort(401) + + user = User.query.filter_by(username=username.lower()).first() + + if not user: + abort(400) + + user.auto_save = auto_save + + db.session.add(user) + db.session.flush() + db.session.commit() + + return jsonify({}), 200 @app.route('/api/search', methods=['POST']) @@ -365,7 +391,9 @@ def search(): cleaned_note['projects'] = sorted(set([x.name for x in note.meta.filter_by(kind="project").all()]), key=lambda s: s.lower()) notes.append(cleaned_note) - return jsonify(notes=notes), 200 + sorted_nodes = sorted(notes, key=lambda s: s['title'].lower()) + + return jsonify(notes=sorted_nodes), 200 @app.route('/', defaults={'path': ''}) diff --git a/client/package-lock.json b/client/package-lock.json index d56e901..5d5399c 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,6 +1,6 @@ { "name": "daily-notes", - "version": "0.1.0", + "version": "1.0.0-beta.11", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -14910,4 +14910,4 @@ } } } -} +} \ No newline at end of file diff --git a/client/package.json b/client/package.json index c51f79b..055d0f7 100644 --- a/client/package.json +++ b/client/package.json @@ -1,7 +1,12 @@ { "name": "daily-notes", - "version": "0.1.0", + "version": "1.0.0-beta.11", "private": true, + "license": "MIT", + "repository": { + "url": "https://github.com/m0ngr31/DailyNotes" + }, + "readme": "https://github.com/m0ngr31/DailyNotes/blob/master/README.md", "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", @@ -55,4 +60,4 @@ "git add" ] } -} +} \ No newline at end of file diff --git a/client/src/components/Header.vue b/client/src/components/Header.vue index 848308d..e0d9bb1 100644 --- a/client/src/components/Header.vue +++ b/client/src/components/Header.vue @@ -76,14 +76,16 @@
- - - - - Settings (coming soon) + + + + + {{ sidebar.autoSave ? 'Disable Auto-Save' : 'Enable Auto-Save' }} + + Logout
diff --git a/client/src/services/requests.ts b/client/src/services/requests.ts index 495874f..d6a550e 100644 --- a/client/src/services/requests.ts +++ b/client/src/services/requests.ts @@ -4,7 +4,9 @@ import {getToken, clearToken, setToken} from './user'; import router from '../router/index'; import {SharedBuefy} from './sharedBuefy'; -axios.defaults.baseURL = '/api'; +axios.defaults.baseURL = process.env.VUE_APP_BASE_URL + ? process.env.VUE_APP_BASE_URL + : '/api'; axios.interceptors.request.use(config => { // Get token diff --git a/client/src/services/sidebar.ts b/client/src/services/sidebar.ts index ea2539b..f9962ae 100644 --- a/client/src/services/sidebar.ts +++ b/client/src/services/sidebar.ts @@ -17,6 +17,7 @@ class SidebarSerivce { public projects: string[] = []; public notes: INote[] = []; public calLoading: boolean = false; + public autoSave: boolean = false; public date: any = null; public sidebarLoading: boolean = false; public searchLoading: boolean = false; @@ -99,6 +100,7 @@ class SidebarSerivce { this.tasks = res.data.tasks; this.projects = res.data.projects; this.notes = res.data.notes; + this.autoSave = res.data.auto_save; } if (this.selectedSearch.length && this.searchString.length) { @@ -138,6 +140,13 @@ class SidebarSerivce { this.getSidebarInfo(); } catch (e) {} } + + public async toggleAutoSave(autoSave: boolean) { + try { + await Requests.post('/toggle_auto_save', {auto_save: autoSave}); + this.getSidebarInfo(); + } catch (e) {} + } } // Make it a singleton diff --git a/client/src/views/Day.vue b/client/src/views/Day.vue index 7039b4c..1a37939 100644 --- a/client/src/views/Day.vue +++ b/client/src/views/Day.vue @@ -231,12 +231,21 @@ export default class Day extends Vue { this.unsavedChanges = true; this.title = `* ${this.headerOptions.title}`; this.headerOptions.saveDisabled = false; + + if (this.sidebar.autoSave) { + this.autoSaveThrottle(); + } } else { this.title = this.headerOptions.title; this.headerOptions.saveDisabled = true; } } + public autoSaveThrottle = _.debounce(() => this.saveDay(), 3000, { + leading: false, + trailing: true + }); + unsavedAlert(e: Event) { if (this.unsavedChanges) { // Attempt to modify event will trigger Chrome/Firefox alert msg diff --git a/client/src/views/Home.vue b/client/src/views/Home.vue index 720ef7d..0c50a31 100644 --- a/client/src/views/Home.vue +++ b/client/src/views/Home.vue @@ -1,14 +1,22 @@