157 Commits

Author SHA1 Message Date
Thomas Peetz 14a4461f6c remove obsolete subprojects
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 4s
2026-06-01 20:12:23 +02:00
Thomas Peetz 81ad30bb45 setup Quarkus app und retrieve Publisher 2026-06-01 20:12:23 +02:00
tpeetz 3893a31e42 Enhance the search field by adding options to filter for boolean fields 2026-06-01 20:12:23 +02:00
Thomas Peetz b04f1aa451 add script to read queues 2026-06-01 20:12:23 +02:00
Thomas Peetz 26f8b992af add servicemix container build 2026-06-01 20:12:23 +02:00
Thomas Peetz 23a48d2472 add add_link.py and improve hamndling of MediaFile 2026-06-01 20:12:23 +02:00
Thomas Peetz 56de399c07 WIP: add HTML form for editing comics 2026-06-01 20:12:23 +02:00
Thomas Peetz 7bc211c9bd add display of issue title in lists 2026-06-01 20:12:23 +02:00
Thomas Peetz 4a6afcfb76 make details for Comic, Artist and Issue clickable, add CustomField to select Comic and Issue 2026-06-01 20:12:23 +02:00
Thomas Peetz 26a91274c2 add IssueWork entity with Repository, Form and View 2026-06-01 20:12:23 +02:00
Thomas Peetz 518a72c6e8 use CustomField to create combined year and month field 2026-06-01 20:12:20 +02:00
Thomas Peetz 02d177fedb add custom component MonthYearPicker 2026-06-01 20:12:20 +02:00
Thomas Peetz 16ee2541dc Remove entity ModuleData and setup data
refs #18
2026-06-01 20:12:20 +02:00
tpeetz 3c5ba33922 remove dependency to MariaDB and improve import of field published_on 2026-06-01 20:12:20 +02:00
tpeetz 1a227d41d7 remove dependency to MariaDB 2026-06-01 20:12:20 +02:00
Thomas Peetz 2d07199bce Add field published_on and title to Issue
/refs #16

Add field published_on and title to Issue and display both fields.
2026-06-01 20:12:08 +02:00
Thomas Peetz b457847178 deactivate authentication 2026-06-01 20:12:08 +02:00
Thomas Peetz 89caedc0d2 move card components to module specific directories 2026-06-01 20:12:08 +02:00
Thomas Peetz e0396eb5a9 remove MetaDataTable and MetaDataColumn to cleanup schema 2026-06-01 20:12:08 +02:00
Thomas Peetz c4705a2d5e add missing fields for import 2026-06-01 20:12:02 +02:00
Thomas Peetz 142c515780 removed fields from MetaDataColumn 2026-06-01 20:12:02 +02:00
Thomas Peetz fab7bd145e add missing fields for comic 2026-06-01 20:12:02 +02:00
Thomas Peetz 230e94aa70 add method for import data 2026-06-01 20:12:02 +02:00
tpeetz fc2a78cd2c update model for import 2026-06-01 20:11:56 +02:00
Thomas Peetz e1fca67157 add reference from Volume to Issue and Comic 2026-06-01 20:11:56 +02:00
Thomas Peetz 57ae257e0c change display of Comics from cards to table 2026-06-01 20:11:56 +02:00
Thomas Peetz 18ef6efc4e add CRUD for WorkType 2026-06-01 20:11:56 +02:00
Thomas Peetz 17f507479a add display for WorkType 2026-06-01 20:11:53 +02:00
Thomas Peetz 6a89ab8d0f add display for MediaVideo 2026-06-01 20:11:53 +02:00
Thomas Peetz 30f9e89c60 add display for MetaData 2026-06-01 20:11:53 +02:00
Thomas Peetz aa375573de add issue display 2026-06-01 20:11:53 +02:00
Thomas Peetz cf49408d0c setup changed 2026-06-01 20:11:53 +02:00
Thomas Peetz 1786fecfed update models to use string type for id fields 2026-06-01 20:11:53 +02:00
Thomas Peetz e5fa32d653 update scripts to use Postgres 2026-06-01 20:11:49 +02:00
Thomas Peetz 595786d126 use PostgreSQL for kontor-spring and kontor-api 2026-06-01 20:11:49 +02:00
Thomas Peetz 19a5623075 import sources from develop/0.1.0 2026-06-01 20:11:49 +02:00
tpeetz c30bdd1cd5 add checking dirs to cjeck_kontor.py 2026-06-01 20:11:49 +02:00
tpeetz 2d706cc3d8 fix problem when deleting MediaFile with MediaActor relations 2026-06-01 20:11:49 +02:00
tpeetz 9cb71f18c2 check for duplicate links 2026-06-01 20:11:49 +02:00
Thomas Peetz 061be5a3b4 add missing endpoints for creating items 2026-06-01 20:11:49 +02:00
tpeetz 330d414e72 synchronize data between configured servers 2026-06-01 20:11:43 +02:00
Thomas Peetz f9d09d5357 update cli scripts to use REST API 2026-06-01 20:11:36 +02:00
Thomas Peetz d862476097 complete loading single items 2026-06-01 20:11:32 +02:00
tpeetz 87c6fb7071 check if more than one server is configured before syncing 2026-06-01 20:11:11 +02:00
Thomas Peetz 3ba1fa40fd add endpoints to get items by id 2026-06-01 20:11:10 +02:00
Thomas Peetz faa1ec44c9 added all missing endpoints 2026-06-01 20:11:06 +02:00
tpeetz 7cdbadbf84 add missing comics endpoints 2026-06-01 20:11:03 +02:00
tpeetz 6310377d84 Remove obsolete endpoints (#89)
Remove endpoints api/login/token and api/login/profile

---------

Co-authored-by: Thomas Peetz <thomas.peetz@cimt-ag.de>
Reviewed-on: #89
2026-06-01 20:11:03 +02:00
tpeetz 7b374b1eeb add mailaccount endpoint 2026-06-01 20:10:43 +02:00
Thomas Peetz fb289ab298 add missing endpoints 2026-06-01 20:10:38 +02:00
tpeetz b2cf1c4698 secure media endpoints 2026-06-01 20:10:21 +02:00
tpeetz f1abf03b35 add missing endpoints 2026-06-01 20:10:14 +02:00
tpeetz eeb2f23e71 remove obsolete scripts 2026-06-01 20:10:04 +02:00
Thomas Peetz ab997d7bbd fix typo in workflow demo.yaml 2026-06-01 20:10:04 +02:00
Thomas Peetz fc89ee2b86 test gitea actions 2026-06-01 20:10:04 +02:00
Thomas Peetz 5ad5a84b09 Add environment variable for DB server 2026-06-01 20:10:04 +02:00
Thomas Peetz 72cafe08ac move *.service files to subdirectory container and add service file for standalone operations in standalone 2026-06-01 20:10:04 +02:00
Thomas Peetz 8cbd04c97a renamed systemd unit files 2026-06-01 20:10:04 +02:00
tpeetz 188f405b23 use separate files for chapters 2026-06-01 20:10:04 +02:00
tpeetz 746fd48de7 add subprojekt kontor-doc 2026-06-01 20:10:04 +02:00
tpeetz fa5f4cfa36 Einrichtung Build 2026-06-01 20:10:04 +02:00
tpeetz b5726af898 integrate kontor-angular 2026-06-01 20:10:04 +02:00
tpeetz b59ecc6ac9 integration von kontor-angular 2026-06-01 20:09:58 +02:00
tpeetz 9dce493c2a rename Dockerfile to Containerfile and integrate kontor-angular in pod kontor 2026-06-01 20:09:58 +02:00
Thomas Peetz 72f6591819 update usage of api for login by email or username 2026-06-01 20:09:48 +02:00
Thomas Peetz 2b7b483019 improve konto-vue/Containerfile by explicitly stating images 2026-06-01 20:09:41 +02:00
tpeetz c8fdb032ea fix OAuth authentication 2026-06-01 20:09:41 +02:00
tpeetz 32971afd94 update systemd service files and add script to copy these files 2026-06-01 20:09:32 +02:00
tpeetz 123c7ef6ef update backend url for profiles 2026-06-01 20:09:26 +02:00
tpeetz 313b07e875 update kontor-vue 2026-06-01 20:09:26 +02:00
tpeetz bba417922c re-setup subproject kontor-vue 2026-06-01 20:09:26 +02:00
tpeetz ea39bbbe1d add Vue 3 subproject 2026-06-01 20:09:22 +02:00
tpeetz 0715e7fdea rename Dockerfile to Containerfile and integrate kontor-vue in pod kontor 2026-06-01 20:09:22 +02:00
tpeetz 17de883bce move build tasks to script/cibuild 2026-06-01 20:09:22 +02:00
tpeetz c9a350bc58 change update_title to add authorization to REST calls 2026-06-01 20:09:22 +02:00
Thomas Peetz 9ffbe2cc2f change MediaActor in all applications ffrom unique name to unique url 2026-06-01 20:09:14 +02:00
Thomas Peetz 9e7d31d903 add temporary access when database is empty 2026-06-01 20:09:11 +02:00
Thomas Peetz c77079c9d9 change reference for Java images 2026-06-01 20:09:06 +02:00
tpeetz d6e2b7daa7 remove MongoDB and Mongo-Express 2026-06-01 20:09:01 +02:00
tpeetz 662bc75b0d add MonfoDB and Mongo-Express to pod 2026-06-01 20:09:01 +02:00
tpeetz 6944b3a209 add kontor-javalin to podman pod 2026-06-01 20:09:01 +02:00
tpeetz 99d3756da7 remove obsolete kontor-gui 2026-06-01 20:09:01 +02:00
tpeetz 182d77354e Add kontor-echo and kontor-fiber to kontor-pod
resolve #35

(cherry picked from commit 05e26e512da9c237adbb58510df2b490837cd836)
2026-06-01 20:09:01 +02:00
tpeetz dc577a9b55 add building of images when images not available
(cherry picked from commit eb7f725994c99bece3185869204aac206d6578b2)
2026-06-01 20:09:01 +02:00
tpeetz 13693aad8b use fully describes images names in container builds with Gradle
(cherry picked from commit 57edf92e30cd3e5bec594399b8a21fc1da31d549)
2026-06-01 20:09:01 +02:00
Thomas Peetz 840ca57428 fixed missing mapping in Comic and type in Rooster
(cherry picked from commit 519c359f94b7e901724c851cc55900448f3f74f4)
2026-06-01 20:08:58 +02:00
Thomas Peetz e0b585f72b refactor kontor-api to use SQLAlchemy 2.0 features for mapping fields
(cherry picked from commit e57abdbef7e13e3880738cd639225df5db0c37be)
2026-06-01 20:08:58 +02:00
tpeetz 47df61af32 update kontor-api
(cherry picked from commit f42735326b4dd490351cebb0fc751d62b3a187d0)
2026-06-01 20:08:36 +02:00
Thomas Peetz b2ce2172a2 Umstellung auf podman in Arbeit
(cherry picked from commit 1a92c63ef6d60e9dcba513ebf60cbd9f18a142e8)
2026-06-01 20:08:26 +02:00
tpeetz 65c4dea710 Add postgres and adminer as container to pod kontor
refs #37

(cherry picked from commit 4469010a74ffefe2d92ffa335d7d1225d12fdece)
2026-06-01 20:08:19 +02:00
tpeetz 5659d116c5 Setup scripts to bootstrap, build and update the aplication
refs #36

The scripts are created and will be extended when adding subprojects.

(cherry picked from commit f688fb939c0f754ab70a4c0a014f00e42ff2f9eb)
2026-06-01 20:08:19 +02:00
tpeetz a196f25526 remove obsolete subprojects
(cherry picked from commit e219932b17bf2b9776141828b3212ed210ffa251)
2026-06-01 20:08:19 +02:00
tpeetz 44fac3f471 Vorbereitung Release 0.2.0 2026-06-01 20:08:13 +02:00
Thomas Peetz 729842a71c remove obsolete subprojects 2025-06-28 22:51:01 +02:00
Thomas Peetz 3d1eeeab53 setup Quarkus app und retrieve Publisher 2025-06-28 22:18:45 +02:00
Thomas Peetz 4871f56320 use new SearchField for Comics 2025-06-23 22:17:45 +02:00
Thomas Peetz ec404c9956 remove servicemix 2025-06-23 12:48:07 +02:00
tpeetz fc9db8200f Merge branch 'feature/6-enhance-the-search-field' into 'develop/0.2.0'
Enhance the search field by adding options to filter for boolean fields

See merge request tpeetz/kontor!22
2025-06-23 12:39:03 +02:00
tpeetz 69caa825de Enhance the search field by adding options to filter for boolean fields 2025-06-23 12:39:03 +02:00
Thomas Peetz 123be2e9c0 add script to read queues 2025-06-20 16:57:17 +02:00
Thomas Peetz 928536b414 add servicemix container build 2025-06-17 23:35:35 +02:00
Thomas Peetz 8ed8599f17 add missing import 2025-06-16 08:08:30 +02:00
Thomas Peetz 435de2ec92 fix handling of id 2025-06-15 05:31:42 +02:00
Thomas Peetz 529a199262 add add_link.py and improve hamndling of MediaFile 2025-06-14 18:53:15 +02:00
Thomas Peetz 510e2f8130 make buttons submit and cancel work 2025-06-13 01:11:18 +02:00
Thomas Peetz da4f286180 remove unused imports 2025-06-11 18:56:33 +02:00
Thomas Peetz d9136e45f6 WIP: add HTML form for editing comics 2025-06-09 23:38:55 +02:00
Thomas Peetz b610947403 change loading config for export.py 2025-06-08 20:23:30 +02:00
Thomas Peetz 6e520a46f0 add display of issue title in lists 2025-06-07 21:39:01 +02:00
Thomas Peetz b4a0c2d7a5 make details for Comic, Artist and Issue clickable, add CustomField to select Comic and Issue 2025-06-05 17:58:27 +02:00
Thomas Peetz ea9f596abe add IssueWork entity with Repository, Form and View 2025-06-04 21:36:26 +02:00
Thomas Peetz 4bb7d61f80 add comparison of datetime objects with strings 2025-06-04 14:06:18 +02:00
Thomas Peetz cc8a166f5c change log.info to log.debug 2025-06-03 13:38:49 +02:00
Thomas Peetz a70bf8ae96 fix selecting Volume for Issue 2025-06-03 10:18:36 +02:00
tpeetz 902ee03e3f Merge branch 'feature/19-create-component-for-selecting-year-and-month' into 'develop/0.2.0'
Resolve "Create component for selecting year and month"

Closes #19

See merge request tpeetz/kontor!19
2025-06-02 22:31:26 +02:00
Thomas Peetz f1f49ab014 use CustomField to create combined year and month field 2025-06-02 22:30:28 +02:00
Thomas Peetz 7a16225c3b add custom component MonthYearPicker 2025-06-02 16:39:03 +02:00
Thomas Peetz 8e13af5b8c add handling of None values 2025-06-02 08:53:40 +02:00
tpeetz 767c069404 Merge branch 'feature/18-remove-entity-moduledata' into 'develop/0.2.0'
Remove entity ModuleData and import data for comic, admin and tysc module

Closes #18

See merge request tpeetz/kontor!20
2025-06-01 22:29:04 +02:00
Thomas Peetz dd5281e2a1 remove entity ModuleData from python code
refs #18
2025-06-01 22:27:42 +02:00
Thomas Peetz aefd56d1ff Remove entity ModuleData and setup data
refs #18
2025-06-01 22:23:25 +02:00
tpeetz 293a0b3478 remove dependency to MariaDB and improve import of field published_on 2025-06-01 20:23:15 +02:00
tpeetz 076466b895 remove dependency to MariaDB 2025-06-01 19:56:01 +02:00
tpeetz 370738ff14 Merge branch 'feature/16-add-publication-date' into 'develop/0.2.0'
Add field published_on and title to Issue

See merge request tpeetz/kontor!18
2025-06-01 18:37:19 +02:00
Thomas Peetz 1151b0e45e Add field published_on and title to Issue
/refs #16

Add field published_on and title to Issue and display both fields.
2025-06-01 18:32:15 +02:00
Thomas Peetz 7c5c571716 add form for editing artist 2025-05-27 18:08:17 +02:00
Thomas Peetz 1b636efdb7 change logging 2025-05-26 11:35:51 +02:00
Thomas Peetz 374c242890 deactivate authentication 2025-05-25 23:10:05 +02:00
Thomas Peetz 87b1c24783 move card components to module specific directories 2025-05-25 22:12:23 +02:00
Thomas Peetz 456162da44 remove MetaDataTable and MetaDataColumn to cleanup schema 2025-05-23 18:21:41 +02:00
Thomas Peetz 8cfb60f9a1 add missing fields for import 2025-05-21 23:24:13 +02:00
Thomas Peetz 4c70046a32 removed fields from MetaDataColumn 2025-05-21 17:29:14 +02:00
Thomas Peetz 546f8ebbdf separate modules for worktype endpoints 2025-05-20 14:06:13 +02:00
Thomas Peetz bd86379d07 add missing fields for comic 2025-05-19 15:14:29 +02:00
Thomas Peetz edcaed1b1a fix problem when adding columns 2025-05-19 14:34:26 +02:00
Thomas Peetz 20ed0b2f40 add method for import data 2025-05-19 14:16:30 +02:00
Thomas Peetz 3197288eee add update for existing items 2025-05-18 15:44:13 +02:00
Thomas Peetz 84d64f04d2 check existing items with data from file 2025-05-15 13:46:05 +02:00
tpeetz 1ecf64a228 update model for import 2025-05-14 19:36:15 +02:00
Thomas Peetz 41d513e402 add reference from Volume to Issue and Comic 2025-05-13 21:40:29 +02:00
Thomas Peetz aa4b47e032 change display of Comics from cards to table 2025-05-13 07:57:58 +02:00
Thomas Peetz 3537642df9 add CRUD for WorkType 2025-05-13 00:42:41 +02:00
Thomas Peetz 06a48a03ac add display for WorkType 2025-05-09 01:17:35 +02:00
Thomas Peetz d60e606663 add display for MediaVideo 2025-05-05 22:13:51 +02:00
Thomas Peetz 13dad3961c add display for MetaData 2025-05-04 12:27:03 +02:00
Thomas Peetz 4cf1941f44 add issue display 2025-05-02 18:17:06 +02:00
Thomas Peetz ace568a800 setup changed 2025-05-02 13:58:09 +02:00
Thomas Peetz c77adb0e04 update models to use string type for id fields 2025-05-02 11:21:57 +02:00
Thomas Peetz 7ff2bf912d update scripts to use Postgres 2025-05-01 01:13:49 +02:00
Thomas Peetz 72c1a7d265 use PostgreSQL for kontor-spring and kontor-api 2025-04-30 22:11:48 +02:00
Thomas Peetz 2efacf6d67 Merge branch 'main' into develop/0.2.0 2025-04-30 19:32:42 +02:00
Thomas Peetz d6549132ea update version to 0.2.0 2025-04-30 19:24:29 +02:00
Thomas Peetz 58f80b3e76 create release 0.1.0 2025-04-30 18:40:24 +02:00
tpeetz ce49c463c3 Merge branch 'develop/0.1.0' into 'main'
remove obsolete kontor.py

See merge request tpeetz/kontor!17
2025-04-30 17:31:18 +02:00
tpeetz 931b4a0aba remove obsolete kontor.py 2025-04-30 17:31:18 +02:00
Thomas Peetz bbf422cc5d create Docker images only with development version as tag 2025-04-29 14:43:07 +02:00
Thomas Peetz 4c96de27db import sources from develop/0.1.0 2025-04-29 12:52:55 +02:00
1457 changed files with 96355 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
name: Gitea Actions Demo
run-name: ${{ gitea.actor }} ist testing out Gitea Actions
on: [push]
jobs:
Explore-Gitea-Actions:
runs-on: inky
steps:
- run: echo "The job was automatically triggered by a ${{ gitea.event_name }} event."
- run: echo "This job is now running on a ${{ runner.os }} server hosted by Gitea!"
- run: echo "The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
- name: Check out repository code
uses: actions/checkout@v4
- run: echo "The ${{ gitea.repository }} repository has been cloned to the runner."
- run: echo "The workflow is now ready to test your code on the runner."
- name: List files in the directory
run: |
ls ${{ gitea.workspace }}
- run: echo "The job's status is ${{ job.status }}."
+20
View File
@@ -0,0 +1,20 @@
.vscode/
.idea/
.angular/
__pycache__/
bonus/
icons/
icons-shadowless/
springboot/.factorypath
java-ee/.settings
java-ee/.project
kontor-schema/env
kontor-schema/kontor_schema.egg-info
kontor-gui/.pdm-python
kontor-gui/dist
fastapi/.coverage
kontor-api/.coverage
db-password.txt
kontor-api/tests/test_main.py
kontor-api/tests/test_db.db
kontor-api/test_db.db
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) 2024 Kontor
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+10
View File
@@ -0,0 +1,10 @@
kontor_api := kontor-api
kontor_spring := kontor-spring
kontor_servicemix := kontor-servicemix
.PHONY: all $(kontor_spring) $(kontor_api)
all: $(kontor_spring) $(kontor_api) $(kontor_servicemix)
$(kontor_spring) $(kontor_api) $(kontor_servicemix):
$(MAKE) --directory=$@ $(TARGET)
+22
View File
@@ -0,0 +1,22 @@
services:
couchdb:
image: couchdb
restart: unless-stopped
environment:
- COUCHDB_USER=admin
- COUCHDB_PASSWORD=admin
ports:
- 5984:5984
networks:
- database
- frontend
volumes:
- couchdb-data:/opt/couchdb/data
secrets:
- couchdb-password
volumes:
couchdb-data:
secrets:
couchdb-password:
file: couchdb-password.txt
+143
View File
@@ -0,0 +1,143 @@
services:
postgres:
image: postgres
restart: unless-stopped
environment:
- POSTGRES_DB=kontor
- POSTGRES_USER=kontor
#- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
- POSTGRES_PASSWORD=kontor
healthcheck:
test: ["CMD-SHELL", "pg_isready -U kontor"]
interval: 1s
timeout: 5s
retries: 10
ports:
- 5432:5432
networks:
- integration
- frontend
volumes:
- postgres-data:/var/lib/postgresql/data:rw
secrets:
- db-password
adminer:
image: adminer
ports:
- 8090:8080
networks:
- database
- frontend
kontor:
image: kontor:0.2.0-SNAPSHOT
restart: unless-stopped
networks:
- database
- integration
- frontend
ports:
- 8000:8000
volumes:
- images-data:/data/images
depends_on:
postgres:
condition: service_healthy
kontor-api:
image: kontor-api:0.2.0-SNAPSHOT
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://kontor-api:8500/health"]
interval: 10s
timeout: 5s
retries: 3
networks:
- database
- integration
- frontend
ports:
- 8500:8500
volumes:
- images-data:/data/images
depends_on:
postgres:
condition: service_healthy
kontor-fiber:
build:
context: ./kontor-fiber
dockerfile: Dockerfile
tags:
- kontor-fiber:0.2.0-SNAPSHOT
image: kontor-fiber:0.2.0-SNAPSHOT
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://kontor-fiber:8600/health"]
interval: 10s
timeout: 5s
retries: 3
networks:
- database
- integration
- frontend
ports:
- 8600:8600
depends_on:
postgres:
condition: service_healthy
kontor-echo:
build:
context: ./kontor-echo
dockerfile: Dockerfile
tags:
- kontor-echo:0.2.0-SNAPSHOT
image: kontor-echo:0.2.0-SNAPSHOT
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://kontor-echo:8700/health"]
interval: 10s
timeout: 5s
retries: 3
networks:
- database
- integration
- frontend
ports:
- 8700:8700
depends_on:
postgres:
condition: service_healthy
kontor-quarkus:
build:
context: ./kontor-quarkus
dockerfile: Dockerfile
tags:
- kontor-quarkus:0.2.0-SNAPSHOT
image: kontor-quarkus:0.2.0-SNAPSHOT
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://kontor-quarkus:8800/q/health"]
interval: 10s
timeout: 5s
retries: 3
networks:
- database
- integration
- frontend
ports:
- 8800:8800
volumes:
- images-data:/data/images
depends_on:
postgres:
condition: service_healthy
networks:
integration:
name: integration
frontend:
volumes:
postgres-data:
images-data:
secrets:
db-password:
file: db-password.txt
+10
View File
@@ -0,0 +1,10 @@
APP_NAME="Kontor"
APP_VERSION="v0.1.0"
# HTTP Response Content-Type Header - Success
HTTP_CONTENT_TYPE="application/vnd.api+json"
# HTTP Response Content-Type Header - Error
HTTP_PROBLEM="application/problem+json"
HTTP_PORT=":8086"
+9
View File
@@ -0,0 +1,9 @@
.gradle/
docs/build/
bin/
build/
cover.out
coverage.html
coverage.xml
.settings/
.project
+116
View File
@@ -0,0 +1,116 @@
variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
before_script:
- source "/home/gitlab-runner/.sdkman/bin/sdkman-init.sh"
- sdk update
- sdk d java 11.0.12-open
stages:
- environment
- prepare
- build
- test
- analysis
- deploy
environment:
stage: environment
script:
- echo "PATH=$PATH:/usr/local/go/bin:/home/gitlab-runner/go/bin" >> build.env
artifacts:
reports:
dotenv: build.env
Prepare Go dependencies:
stage: prepare
script:
- go get -u github.com/spf13/cobra
- go get -u github.com/jstemmer/go-junit-report
- go get -u github.com/inconshreveable/mousetrap
- go get -u github.com/mitchellh/go-homedir
- go get github.com/boumenot/gocover-cobertura
- go get -u gotest.tools/gotestsum
- go get -u github.com/cryptix/wav
- go get -u golang.org/x/lint/golint
dependencies:
- environment
Create Documentation:
stage: build
script:
- chmod +x docs/gradlew
- cd docs; ./gradlew publish
Compile Go Application:
stage: build
script: make build
Test Go Application:
stage: test
script:
- gotestsum --junitfile report.xml --format testname -- -coverprofile=coverage.txt -covermode count ./...
- go vet ./... 2> govet-report.out
- gocover-cobertura < coverage.txt > coverage.xml
- golint ./... > golint-report.out
dependencies:
- environment
artifacts:
when: always
paths:
- coverage.xml
- report.xml
reports:
junit: report.xml
coverage_report:
coverage_format: cobertura
path: coverage.xml
Code analysis:
stage: analysis
script:
- go test -coverprofile cover.out ./... -json > report.json
- go vet ./... 2> govet-report.out
- golint ./... > golint-report.out
- echo "sonar.projectKey=kontor_kontor-go_AX-cQT62rXuu6JVRvr-z" >> sonar-project.properties
- echo "sonar.sources=." >> sonar-project.properties
- echo "sonar.exclusions=**/*_test.go" >> sonar-project.properties
- echo "sonar.tests=." >> sonar-project.properties
- echo "sonar.test.inclusions=**/*_test.go" >> sonar-project.properties
- echo "sonar.go.tests.reportPaths=report.json" >> sonar-project.properties
- echo "sonar.go.coverage.reportPaths=cover.out" >> sonar-project.properties
- echo "sonar.go.govet.reportPaths=govet-report.out" >> sonar-project.properties
- echo "sonar.go.golint.reportPaths=golint-report.out" >> sonar-project.properties
- /data/sonar-scanner/bin/sonar-scanner -Dsonar.projectVersion=$(git describe --abbrev=0) -Dsonar.host.url=https://sonar.thpeetz.de -Dsonar.login=319616a2761ac3e96a1c7aacc54976bfff4096a9
dependencies:
- environment
Deploy To Staging:
stage: deploy
script:
- make build
- ssh kontor /home/kontor/kontor-test_service stop
- rsync -av templates kontor:/home/kontor/staging
- rsync -av bin/kontor kontor:/home/kontor/staging
- ssh kontor /home/kontor/kontor-test_service start
environment:
name: staging
url: https://kontor-test.thpeetz.de
only:
- main
Deploy to Production:
stage: deploy
script:
- make build
- sudo service kontor stop
- rsync -av templates kontor:/home/kontor/production
- rsync -av bin/kontor kontor:/home/kontor/production
- sudo service kontor start
environment:
name: production
url: https://kontor.thpeetz.de
only:
- main
when: manual
+73
View File
@@ -0,0 +1,73 @@
# Go parameters
GOPATH=$(HOME)/go
#GOBIN=$(shell pwd)/bin
GOBIN=/usr/local/go/bin
GOCMD=$(GOBIN)/go
GOGET=$(GOCMD) get
GOBUILD=$(GOCMD) build
GOCLEAN=$(GOCMD) clean
GOTEST=$(GOCMD) test
GOCOVER=$(GOCMD) tool cover
COBERTURA=$(HOME)/go/bin/gocover-cobertura
GOLINT=$(GOBIN)/golint
GOVET=$(GOCMD) vet
# Project parameters
GONAME=kontor
GOFILE=cmd/kontor/main.go
#.PHONY: all deps clean clean-bin clean-doc
all: deps build
deps:
$(GOGET) -u -v github.com/jstemmer/go-junit-report
$(GOGET) -u -v github.com/tebeka/go2xunit
$(GOGET) -u -v github.com/t-yuki/gocover-cobertura
$(GOGET) -u -v github.com/spf13/cobra/cobra
$(GOGET) -u -v github.com/inconshreveable/mousetrap
$(GOGET) -u -v github.com/mitchellh/go-homedir
$(GOGET) -u -v github.com/golang/protobuf/proto
$(GOGET) -u -v github.com/gin-gonic/gin
$(GOGET) -u -v github.com/gin-gonic/gin/binding
$(GOGET) -u -v github.com/gin-gonic/gin/render
$(GOGET) -u -v github.com/gin-contrib/sse
$(GOGET) -u -v github.com/mattn/go-isatty
$(GOGET) -u -v github.com/ugorji/go/codec
$(GOGET) -u -v golang.org/x/crypto/bcrypt
$(GOGET) -u -v golang.org/x/crypto/blowfish
G$(GOGET) -u -v gopkg.in/yaml.v2
$(GOGET) -u -v gopkg.in/mgo.v2
$(GOGET) -u -v gopkg.in/mgo.v2/bson
build: bin/$(GONAME)
bin/$(GONAME): $(GOFILE)
@echo "Building $(GOFILE) to ./bin"
$(GOBUILD) -v -ldflags="-X main.version=$(shell git describe --always --long --dirty)" -o bin/$(GONAME) $(GOFILE)
install:
@echo using $(GOPATH)
$(GOCMD) install -v -ldflags="-X main.version=$(shell git describe --always --long --dirty)" ./...
test:
$(GOTEST) -v ./...
$(GOTEST) -coverprofile=cover.out ./...
$(GOCOVER) -html=cover.out -o coverage.html
$(COBERTURA) < cover.out > coverage.xml
$(GOLINT) ./...
$(GOVET) -v ./...
doc:
cd docs; ./gradlew build
clean: clean-doc clean-bin
clean-doc:
@echo "Cleaning Gradle build"
cd docs; ./gradlew clean
clean-bin:
@echo "Cleaning Go build"
rm -rf bin/
+4
View File
@@ -0,0 +1,4 @@
[![pipeline status](https://gitlab.thpeetz.de/kontor/kontor-go/badges/master/pipeline.svg)](https://gitlab.thpeetz.de/kontor/kontor-go/commits/master)
[![coverage report](https://gitlab.thpeetz.de/kontor/kontor-go/badges/master/coverage.svg)](https://gitlab.thpeetz.de/kontor/kontor-go/commits/master)
# Kontor
+36
View File
@@ -0,0 +1,36 @@
package main
import (
"database/sql"
"log"
"time"
_ "github.com/go-sql-driver/mysql"
)
func main() {
connectionString := "kontor:kontor@tcp(127.0.0.1:3306)/kontor?parseTime=true"
db, err := sql.Open("mysql", connectionString)
if err != nil {
log.Printf("setup database error: %v", err)
return
}
db.SetConnMaxLifetime(time.Minute * 3)
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(10)
log.Println("Database connected")
rows, err := db.Query("SELECT id, created_date, last_modified_date, version, url, title, review FROM media_file")
if err != nil {
log.Fatal((err.Error()))
}
defer rows.Close()
var rec MediaFile
for rows.Next() {
err = rows.Scan(&rec.ID, &rec.CreatedDate, &rec.LastModifiedDate, &rec.Version, &rec.Url, &rec.Title, &rec.Review)
if err != nil {
log.Fatal(err.Error())
}
log.Println(rec, string(rec.Url), string(rec.Title))
}
}
+25
View File
@@ -0,0 +1,25 @@
package main
import (
"time"
"github.com/google/uuid"
)
type AbstractEntity struct {
ID uuid.UUID `gorm:"type:uuid;primary_key" json:"id"`
Version uint `json:"version"`
CreatedDate time.Time `json:"createdDate"`
LastModifiedDate time.Time `json:"lastModifiedDate"`
}
type MediaFile struct {
AbstractEntity
Url []byte `json:"url"`
Review []uint8 `json:"review"`
ShouldDownload []uint8 `json:"shouldDownload"`
Title []byte `json:"title"`
CloudLink string `json:"cloudLink"`
FileName string `json:"fileName"`
Path string `json:"path"`
}
+89
View File
@@ -0,0 +1,89 @@
package cmd
import (
"fmt"
"log"
"os"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/properties"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/setup"
"github.com/gin-gonic/gin"
"github.com/spf13/cobra"
)
var (
// Verbose defines the parameter verbose.
Verbose bool
// Version defines the version of the web application.
Version string
// Debug defines the debug parameter.
Debug bool
// Port defines the parameter port.
Port int
// TemplatesDir defines the root directory of template files.
TemplatesDir string
router *gin.Engine
)
var rootCmd = &cobra.Command{
Use: "kontor",
Short: "kontor",
Long: `kontor`,
Run: func(cmd *cobra.Command, args []string) {
// Set Gin to production mode
if Debug {
gin.SetMode(gin.DebugMode)
} else {
gin.SetMode(gin.ReleaseMode)
}
log.SetOutput(gin.DefaultWriter)
// Set the router as the default one provided by Gin
router = gin.Default()
// Process the templates at the start so that they don't have to be loaded
// from the disk again. This makes serving HTML pages very fast.
templatesDir := fmt.Sprintf("%s/**/*", TemplatesDir)
log.Printf("load template files from %v", templatesDir)
router.LoadHTMLGlob(templatesDir)
// Use Middleware logger
router.Use(gin.Logger())
// Initialize the routes
setup.InitializeRoutes(router)
// Clean up SetSessionStatus
setup.CleanupSessions()
// Check if at least one user configured
setup.CheckUserList()
// Check if data for TradeYourSportsCards is available
setup.CheckTradeYourSportsCardsData()
//properties.SetVersion(Version)
// Start serving the application
server := fmt.Sprintf("127.0.0.1:%d", Port)
router.Run(server)
},
}
// Execute parses the commandline and calls Execute on rootCmd.
func Execute(version string) {
rootCmd.Version = version
properties.SetVersion(version)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func init() {
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
rootCmd.PersistentFlags().BoolVarP(&Debug, "debug", "d", false, "debug modus")
rootCmd.PersistentFlags().IntVarP(&Port, "port", "p", 8500, "port number")
rootCmd.PersistentFlags().StringVarP(&TemplatesDir, "templates", "t", "templates", "path for template files")
}
+32
View File
@@ -0,0 +1,32 @@
package main
import (
"github.com/joho/godotenv"
application "gitlab.com/tpeetz-kontor/kontor-go/pkg/infrastructure/app"
"gitlab.com/tpeetz-kontor/kontor-go/pkg/infrastructure/kernel"
)
// init is invoked before main()
func init() {
// loads values from .env into the system
if err := godotenv.Load(); err != nil {
panic("No .env file found")
}
}
func main() {
// Create our application
app := kernel.Boot()
// Build our services
//ping.BuildPingService(app)
// Run our Application in a coroutine
go func() {
app.Run()
}()
// Wait for termination signals and shut down gracefully
application.WaitForShutdown(app)
}
+63
View File
@@ -0,0 +1,63 @@
<Comics>
<Publisher name="Marvel" id="1"/>
<Publisher name="Aspen" id="2"/>
<Publisher name="DC" id="3"/>
<Publisher name="Dynamite Entertainment" id="4"/>
<Publisher name="WildStorm" id="5"/>
<Publisher name="Bongo" id="6"/>
<Publisher name="Image" id="7"/>
<Publisher name="Dark Horse Comics" id="8"/>
<Publisher name="Cliffhanger" id="9"/>
<Artist name="Turner, Michael" id="1"/>
<Artist name="Whedon, Joss" id="4"/>
<Artist name="Land, Greg" id="3"/>
<Artist name="Bendis, Brian Michael" id="2"/>
<Comic title="X-Men" id="1" publisher_id="1" current_order="true" completed="false"/>
<Comic title="Red Sonja" id="3" publisher_id="4" current_order="true" completed="false"/>
<Comic title="X-23" id="2" publisher_id="1" current_order="false" completed="false"/>
<Comic title="Simpsons Comics" id="4" publisher_id="6" current_order="true" completed="false"/>
<Comic title="Futurama Comics" id="5" publisher_id="6" current_order="true" completed="false"/>
<Comic title="Bomb Queen III: The Good, The Bad and The Lovely" id="7" publisher_id="7" current_order="false" completed="true"/>
<Comic title="Bomb Queen IV: Suicide Bomber" id="8" publisher_id="7" current_order="true" completed="false"/>
<Comic title="Gen13" id="9" publisher_id="5" current_order="true" completed="false"/>
<Comic title="Bomb Queen II: Queen of Hearts" id="6" publisher_id="7" current_order="false" completed="true"/>
<Comic title="Iron &amp; The Maiden" id="10" publisher_id="2" current_order="true" completed="false"/>
<Comic title="Fathom" id="11" publisher_id="2" current_order="false" completed="false"/>
<Comic title="Soulfire" id="12" publisher_id="2" current_order="false" completed="false"/>
<Comic title="Star Wars: Rebellion" id="13" publisher_id="8" current_order="false" completed="false"/>
<Comic title="Star Wars: Knights of the Old Republic" id="14" publisher_id="8" current_order="false" completed="false"/>
<Comic title="Star Wars: Legacy" id="15" publisher_id="8" current_order="false" completed="false"/>
<Comic title="Star Wars: Dark Times" id="16" publisher_id="8" current_order="false" completed="false"/>
<Comic title="Samurai: Heaven and Earth" id="17" publisher_id="8" current_order="false" completed="false"/>
<Comic title="Battle Pope" id="18" publisher_id="7" current_order="true" completed="false"/>
<Comic title="Danger Girl" id="19" publisher_id="9" current_order="false" completed="true"/>
<Comic title="Marville" id="20" publisher_id="1" current_order="false" completed="true"/>
<StoryArc title="Test" id="1" comic_id="1"/>
<Issue number="0" id="3" comic_id="3" cover_id="3" gelesen="true"/>
<Issue number="1" id="2" comic_id="2" cover_id="1" gelesen="false"/>
<Issue number="1" id="6" comic_id="6" gelesen="false"/>
<Issue number="1" id="4" comic_id="3" gelesen="true"/>
<Issue number="2" id="5" comic_id="3" gelesen="true"/>
<Issue number="2" id="7" comic_id="6" gelesen="false"/>
<Issue number="3" id="8" comic_id="6" gelesen="false"/>
<Issue number="4" id="9" comic_id="6" gelesen="false"/>
<Issue number="1" id="10" comic_id="18" gelesen="false"/>
<Issue number="2" id="11" comic_id="18" gelesen="false"/>
<Issue number="3" id="12" comic_id="18" gelesen="false"/>
<Issue number="4" id="13" comic_id="18" gelesen="false"/>
<Issue number="5" id="14" comic_id="18" gelesen="false"/>
<Issue number="6" id="15" comic_id="18" gelesen="false"/>
<Issue number="7" id="16" comic_id="18" gelesen="false"/>
<Issue number="8" id="17" comic_id="18" gelesen="false"/>
<Issue number="9" id="18" comic_id="18" gelesen="false"/>
<Issue number="10" id="19" comic_id="18" gelesen="false"/>
<Issue number="11" id="20" comic_id="18" gelesen="false"/>
<Issue number="12" id="21" comic_id="18" gelesen="false"/>
<Issue number="1" id="22" comic_id="20" gelesen="false"/>
<Issue number="2" id="23" comic_id="20" gelesen="false"/>
<Issue number="3" id="24" comic_id="20" gelesen="false"/>
<Issue number="4" id="25" comic_id="20" gelesen="false"/>
<Issue number="5" id="26" comic_id="20" gelesen="false"/>
<Issue number="6" id="27" comic_id="20" gelesen="false"/>
<Issue number="7" id="28" comic_id="20" gelesen="false"/>
</Comics>
+7
View File
@@ -0,0 +1,7 @@
plugins {
alias(versionsLibs.plugins.asciidoctorConvention)
}
wrapper {
gradleVersion = "7.5"
}
+2
View File
@@ -0,0 +1,2 @@
description='Documentation for application kontor-go'
version=1.0.0-SNAPSHOT
Binary file not shown.
+5
View File
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored Executable
+240
View File
@@ -0,0 +1,240 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
+91
View File
@@ -0,0 +1,91 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+1
View File
@@ -0,0 +1 @@
rootProject.name='kontor-go'
+31
View File
@@ -0,0 +1,31 @@
= Projektbeschreibung Kontor
:author: Thomas Peetz
:email: <thomas.peetz@ingenieurbuero-peetz.de>
:doctype: article
:toc: left
:sectnums:
== Einführung
=== Zweck
== Anforderungen
== Implementierung
=== Datenmodell
== Betrieb
[bibliography]
== Referenzen
- [[[1]]] Thomas Peetz, Betriebshandbuch IBTP
[index]
== Index
== Tabellenverzeichnis
[glossary]
== Glossar
+28
View File
@@ -0,0 +1,28 @@
module gitlab.com/tpeetz-kontor/kontor-go
go 1.22.2
require github.com/joho/godotenv v1.5.1
require (
github.com/felixge/httpsnoop v1.0.3 // indirect
go.uber.org/multierr v1.10.0 // indirect
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/google/uuid v1.6.0
github.com/gorilla/handlers v1.5.2
github.com/gorilla/mux v1.8.1
github.com/jinzhu/gorm v1.9.16 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
go.uber.org/zap v1.27.0
golang.org/x/text v0.19.0 // indirect
golang.org/x/tools v0.21.1-0.20240531212143-b6235391adb3 // indirect
gorm.io/driver/mysql v1.5.7 // indirect
gorm.io/gorm v1.25.12 // indirect
)
+62
View File
@@ -0,0 +1,62 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.21.1-0.20240531212143-b6235391adb3 h1:SHq4Rl+B7WvyM4XODon1LXtP7gcG49+7Jubt1gWWswY=
golang.org/x/tools v0.21.1-0.20240531212143-b6235391adb3/go.mod h1:bqv7PJ/TtlrzgJKhOAGdDUkUltQapRik/UEHubLVBWo=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=
honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs=
+58
View File
@@ -0,0 +1,58 @@
---
# file: kontor-ansible.yml
- hosts: localhost
remote_user: root
tasks:
- name: create group kontor
group:
name: kontor
state: present
- name: create user kontor
user:
name: kontor
home: /home/kontor
shell: /bin/bash
state: present
# generate_ssh_key: yes
# ssh_key_bits: 4096
# ssh_key_file: .ssh/id_rsa
- name: create log directory
file:
path: /var/log/kontor
state: directory
owner: kontor
group: kontor
mode: 0775
recurse: true
- name: create run directory
file:
path: /var/run/kontor
state: directory
owner: kontor
group: kontor
mode: 0775
recurse: true
- name: create directory
file:
path: /home/kontor/production
state: directory
owner: kontor
group: kontor
mode: 0775
recurse: false
- name: copy binary
copy:
src: bin/kontor
dest: /home/kontor/production/kontor
mode: 0775
- name: copy templates
copy:
src: templates
dest: /home/kontor/production/kontor/templates
mode: 0775
+23
View File
@@ -0,0 +1,23 @@
package admin
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/auth"
"github.com/gin-gonic/gin"
)
// GetRoutes sets the routes for the administrative data urls.
func GetRoutes(router *gin.Engine) {
adminRoutes := router.Group("/admin")
{
adminRoutes.GET("/", auth.EnsureLoggedIn(), auth.EnsureAdminStatus(), showAdminIndex)
adminRoutes.GET("/user", auth.EnsureLoggedIn(), auth.EnsureAdminStatus(), showUserIndex)
adminRoutes.POST("/user", auth.EnsureLoggedIn(), auth.EnsureAdminStatus(), showUserIndex)
adminRoutes.GET("/user/view/:userid", auth.EnsureLoggedIn(), auth.EnsureAdminStatus(), showUserDetails)
adminRoutes.POST("/user/view", auth.EnsureLoggedIn(), auth.EnsureAdminStatus(), validateUserCreation)
adminRoutes.GET("/user/create", auth.EnsureLoggedIn(), auth.EnsureAdminStatus(), showUserCreation)
adminRoutes.POST("/user/create", auth.EnsureLoggedIn(), auth.EnsureAdminStatus(), validateUserCreation)
adminRoutes.GET("/data", auth.EnsureLoggedIn(), auth.EnsureAdminStatus(), showDataUpload)
adminRoutes.POST("/data", auth.EnsureLoggedIn(), auth.EnsureAdminStatus(), validateDataUpload)
}
}
+18
View File
@@ -0,0 +1,18 @@
package admin
import (
"gopkg.in/mgo.v2/bson"
)
// User defines the data model for application users with id,email, user name,
// first and family name, password and admin status.
type User struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Email string `json:"email" bson:"email,omitempty"`
Username string `json:"username" bson:"username,omitempty"`
Firstname string `json:"firstname" bson:"firstname,omitempty"`
Lastname string `json:"lastname" bson:"lastname,omitempty"`
Password string `json:"password" bson:"password,omitempty"`
IsAdmin bool `json:"is_admin" bson:"is_admin,omitempty"`
Model string `json:"model" bson:"model,omitempty"`
}
+123
View File
@@ -0,0 +1,123 @@
package admin
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"log"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// UserDAO extends the type BaseDAO.
type UserDAO struct {
Db dao.BaseDAO
}
const (
// USERCOLLECTION defines the collection name for storing application user data.
USERCOLLECTION = "user"
// USERMODEL defines the name of the user data model.
USERMODEL = "kontor.admin.user"
)
// HashPassword returns the encrypted password from password string.
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
return string(bytes), err
}
// CheckPasswordHash returns if password correlates with pasword hash.
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
// FindAll retrieves the list of users from the database.
func (m *UserDAO) FindAll() ([]User, error) {
m.Db.Connect()
var users []User
err := m.Db.MongoDb.C(USERCOLLECTION).Find(bson.M{"model": USERMODEL}).All(&users)
return users, err
}
// FindByID returns a user with given id or returns the error.
func (m *UserDAO) FindByID(id string) (User, error) {
m.Db.Connect()
var user User
err := m.Db.MongoDb.C(USERCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&user)
return user, err
}
// FindByUsername returns a user with given name or returns the error.
func (m *UserDAO) FindByUsername(username string) (User, error) {
m.Db.Connect()
var user User
err := m.Db.MongoDb.C(USERCOLLECTION).Find(bson.M{"username": username, "model": USERMODEL}).One(&user)
return user, err
}
// Insert a user into database.
func (m *UserDAO) Insert(user User) error {
m.Db.Connect()
user.Model = USERMODEL
err := m.Db.MongoDb.C(USERCOLLECTION).Insert(&user)
return err
}
// Upsert a user into database.
func (m *UserDAO) Upsert(user User) (*mgo.ChangeInfo, error) {
m.Db.Connect()
user.Model = USERMODEL
info, err := m.Db.MongoDb.C(USERCOLLECTION).Upsert(bson.M{"username": user.Username}, &user)
return info, err
}
// Update an existing user.
func (m *UserDAO) Update(user User) error {
m.Db.Connect()
err := m.Db.MongoDb.C(USERCOLLECTION).UpdateId(user.ID, &user)
return err
}
// Delete an existing user.
func (m *UserDAO) Delete(user User) error {
m.Db.Connect()
err := m.Db.MongoDb.C(USERCOLLECTION).Remove(&user)
return err
}
// IsUserValid checks if the username and password combination is valid
func (m *UserDAO) IsUserValid(username, password string) bool {
if gin.IsDebugging() {
log.Printf("UserDAO.IsUserValid(%s)", username)
}
user, err := m.FindByUsername(username)
if gin.IsDebugging() {
log.Printf("UserDAO.IsUserValid: %v, %v", user, err)
}
if &user == nil || err != nil {
return false
}
return CheckPasswordHash(password, user.Password)
}
// IsUserAdmin checks if user identified by name has admin rights.
func (m *UserDAO) IsUserAdmin(username string) bool {
user, err := m.FindByUsername(username)
if &user == nil || err != nil {
return false
}
return user.IsAdmin
}
// IsUsernameAvailable checks if the supplied username is available.
func (m *UserDAO) IsUsernameAvailable(username string) bool {
user, err := m.FindByUsername(username)
if &user == nil || err != nil {
return true
}
return false
}
+105
View File
@@ -0,0 +1,105 @@
package admin
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var userModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Email", "string"},
{"Username", "string"},
{"Firstname", "string"},
{"Lastname", "string"},
{"Password", "string"},
{"IsAdmin", "bool"},
{"Model", "string"},
}
func TestUserModel(t *testing.T) {
m := User{}
if reflect.TypeOf(m).NumField() != len(userModelTestTable) {
t.Fail()
}
for index, testData := range userModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListUsers(t *testing.T) {
var userDao = UserDAO{Db: dao.TestDb}
users, err := userDao.FindAll()
if err != nil {
t.Fail()
}
if users != nil {
t.Fail()
}
}
func TestInsertUser(t *testing.T) {
var (
userDao = UserDAO{Db: dao.TestDb}
user = User{}
users []User
)
user.ID = bson.NewObjectId()
user.Username = "test"
err := userDao.Insert(user)
if err != nil {
t.Fail()
}
users, err = userDao.FindAll()
if err != nil {
t.Fail()
}
if len(users) != 1 {
t.Fail()
}
}
func TestUpsertUser(t *testing.T) {
var (
userDao = UserDAO{Db: dao.TestDb}
user = User{}
)
user.ID = bson.NewObjectId()
user.Username = "test2"
userDao.Upsert(user)
users, err := userDao.FindAll()
if err != nil {
t.Fail()
}
if len(users) != 2 {
t.Fail()
}
}
func TestDeleteUser(t *testing.T) {
var (
userDao = UserDAO{Db: dao.TestDb}
)
users, err := userDao.FindAll()
if err != nil {
t.Fail()
}
for _, user := range users {
userDao.Delete(user)
}
users, err = userDao.FindAll()
if err != nil {
t.Fail()
}
if len(users) != 0 {
t.Fail()
}
}
+242
View File
@@ -0,0 +1,242 @@
package admin
import (
"io/ioutil"
"log"
"net/http"
"path/filepath"
"strconv"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/auth"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/comics"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/util"
"github.com/gin-gonic/gin"
"github.com/smallfish/simpleyaml"
)
const (
// KontorUserAdministrationTitle defines the text of the page title
KontorUserAdministrationTitle = "Kontor User Administration"
// DataUploadTemplate defines the name of the template file for the data upload
DataUploadTemplate = "kontor/data-upload.html"
)
// ShowLoginPage renders login page.
func ShowLoginPage(c *gin.Context) {
// Call the render function with the name of the template to render
util.Render(c, gin.H{"title": "Login"}, "login.html")
}
// PerformLogin reads data from login form and validates input.
func PerformLogin(c *gin.Context) {
// Obtain the POSTed username and password values
username := c.PostForm("username")
password := c.PostForm("password")
var userDao = UserDAO{Db: dao.KontorDb}
// Check if the username/password combination is valid
if userDao.IsUserValid(username, password) {
sessionInterface, _ := c.Get("session")
sessionID := sessionInterface.(string)
user, _ := userDao.FindByUsername(username)
sessionDao := auth.SessionDAO{Db: dao.KontorDb}
session, _ := sessionDao.FindByID(sessionID)
session.Username = username
session.IsAdmin = user.IsAdmin
sessionDao.Update(session)
util.Render(c, gin.H{"title": "Successful Login", "InfoMessage": "Login successfull"}, "kontor/index.html")
} else {
// If the username/password combination is invalid,
// show the error message on the login page
c.HTML(http.StatusBadRequest, "login.html", gin.H{
"ErrorTitle": "Login Failed",
"ErrorMessage": "Invalid credentials provided"})
}
}
// Logout invalidates session.
func Logout(c *gin.Context) {
sessionInterface, _ := c.Get("session")
sessionID := sessionInterface.(string)
c.SetCookie("session", sessionID, -1, "", "", false, true)
// Redirect to the home page
c.Redirect(http.StatusTemporaryRedirect, "/")
}
func showAdminIndex(c *gin.Context) {
// Call the render function with the name of the template to render
util.Render(c, gin.H{"title": "Kontor", "payload": nil}, "kontor/admin.html")
}
func showUserIndex(c *gin.Context) {
var dao = UserDAO{Db: dao.KontorDb}
if users, err := dao.FindAll(); err == nil && users != nil {
util.Render(c, gin.H{"title": KontorUserAdministrationTitle, "payload": users}, "kontor/users.html")
} else {
util.Render(c, gin.H{"title": KontorUserAdministrationTitle, "payload": users, "ErrorMessage": err}, "kontor/users.html")
}
}
func showUserDetails(c *gin.Context) {
userID := c.Param("userid")
var userDao = UserDAO{Db: dao.KontorDb}
if user, err := userDao.FindByID(userID); err == nil && &user != nil {
util.Render(c, gin.H{"title": KontorUserAdministrationTitle, "payload": user, "action": util.SaveAction}, "kontor/user-detail.html")
} else {
c.AbortWithError(http.StatusNotFound, err)
}
}
func showUserCreation(c *gin.Context) {
var user = User{}
util.Render(c, gin.H{"title": KontorUserAdministrationTitle, "payload": user, "action": util.AddAction}, "kontor/user-detail.html")
}
func validateUserCreation(c *gin.Context) {
// Obtain the POSTed username and password values
username := c.PostForm("username")
firstname := c.PostForm("firstname")
lastname := c.PostForm("lastname")
password := c.PostForm("password")
adminFormVar := c.PostForm("admin")
action := c.PostForm("action")
userid := c.PostForm("userid")
isAdmin, _ := strconv.ParseBool(adminFormVar)
var err error
var dao = UserDAO{Db: dao.KontorDb}
var user = User{}
switch action {
case util.AddAction:
user.Username = username
user.Firstname = firstname
user.Lastname = lastname
user.IsAdmin = isAdmin
user.Password, _ = HashPassword(password)
_, err = dao.Upsert(user)
case util.SaveAction:
user, _ = dao.FindByID(userid)
user.Username = username
user.Firstname = firstname
user.Lastname = lastname
user.IsAdmin = isAdmin
user.Password, _ = HashPassword(password)
err = dao.Update(user)
case util.DeleteAction:
user, _ = dao.FindByID(userid)
err = dao.Delete(user)
}
if err == nil {
c.Redirect(http.StatusTemporaryRedirect, "/admin/user")
} else {
c.HTML(http.StatusBadRequest, "kontor/create-user.html", gin.H{
"ErrorTitle": "User Creation Failed",
"ErrorMessage": err.Error()})
}
}
func showDataUpload(c *gin.Context) {
// Call the render function with the name of the template to render
//util.Render(c, gin.H{"title": "Kontor", "payload": nil}, "kontor/admin.html")
util.Render(c, gin.H{"title": "Kontor Data Upload", "payload": nil}, DataUploadTemplate)
}
func validateDataUpload(c *gin.Context) {
// Call the render function with the name of the template to render
//util.Render(c, gin.H{"title": "Kontor", "payload": nil}, "kontor/admin.html")
datafile, err := c.FormFile("datafile")
if err != nil {
c.HTML(http.StatusBadRequest, DataUploadTemplate, gin.H{
"ErrorTitle": "Data Upload Failed",
"ErrorMessage": err.Error()})
return
}
log.Printf("Data File: %v", datafile.Filename)
filename := filepath.Base(datafile.Filename)
if err := c.SaveUploadedFile(datafile, filename); err != nil {
c.HTML(http.StatusBadRequest, DataUploadTemplate, gin.H{
"ErrorTitle": "Data Upload Failed",
"ErrorMessage": err.Error()})
return
}
source, err := ioutil.ReadFile(filename)
if err != nil {
panic(err)
}
yaml, err := simpleyaml.NewYaml(source)
if err != nil {
panic(err)
}
if yaml.IsArray() {
size, err := yaml.GetArraySize()
if err != nil {
panic(err)
}
log.Printf("Found %d entries.\n", size)
var publisherDao comics.PublisherDAO
publisherDao.Db = dao.KontorDb
var artistDao comics.ArtistDAO
artistDao.Db = dao.KontorDb
var comicDao comics.ComicDAO
comicDao.Db = dao.KontorDb
publisherMap := make(map[int]string)
for index := 0; index < size; index++ {
entry := yaml.GetIndex(index)
if entry.IsMap() {
model, err := entry.Get("model").String()
if err != nil {
panic(err)
}
pk, _ := entry.Get("pk").Int()
switch model {
case "comics.publisher":
name, err := entry.Get("fields").Get("name").String()
if err != nil {
panic(err)
}
log.Printf(" %v %v %v\n", pk, model, name)
publisherMap[pk] = name
publisher := comics.Publisher{}
publisher.Name = name
info, _ := publisherDao.Upsert(publisher)
log.Printf("Publisher records changed: %d", info.Updated)
case "comics.artist":
name, err := entry.Get("fields").Get("name").String()
if err != nil {
panic(err)
}
log.Printf(" %v %v %v\n", pk, model, name)
artist := comics.Artist{}
artist.Name = name
info, _ := artistDao.Upsert(artist)
log.Printf("Artist records changed: %d", info.Updated)
case "comics.comic":
title, err := entry.Get("fields").Get("title").String()
if err != nil {
panic(err)
}
publisherID, err := entry.Get("fields").Get("publisher").Int()
publisher, err := publisherDao.FindByName(publisherMap[publisherID])
completed, err := entry.Get("fields").Get("completed").Bool()
if err != nil {
log.Printf("Error occured: %v", err)
}
log.Printf(" %v %v %v %v\n", pk, model, title, completed)
comic := comics.Comic{}
comic.Title = title
comic.Completed = completed
comic.Publisher = publisher.ID
info, _ := comicDao.Upsert(comic)
log.Printf("Comic records changed: %d", info.Updated)
}
//fmt.Printf("Entry %d: %v\n", index, entry)
}
}
}
util.Render(c, gin.H{"title": "Kontor Data Upload", "payload": nil}, DataUploadTemplate)
}
@@ -0,0 +1,19 @@
package comic
import (
"net/http"
"gitlab.com/tpeetz-kontor/kontor-go/cmd/pkg/context/comic/routing"
"gitlab.com/tpeetz-kontor/kontor-go/cmd/pkg/infrastructure/app"
)
func BuildComicService(app *app.Application) {
// Create our Handler
handler := routing.NewHandler(app)
// Create a sub router for this service
router := app.Router.Methods(http.MethodGet).Subrouter()
// Register our service routes
router.HandleFunc("/comics/comic", handler.ComicList).Name("comics:comicList")
}
+87
View File
@@ -0,0 +1,87 @@
package auth
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/properties"
"log"
"net/http"
"github.com/gin-gonic/gin"
"gopkg.in/mgo.v2/bson"
)
var sessionDao = SessionDAO{Db: dao.KontorDb}
// EnsureLoggedIn ensures that a request will be aborted with an error
// if the user is not logged in
func EnsureLoggedIn() gin.HandlerFunc {
return func(c *gin.Context) {
// If there's an error or if the token is empty
// the user is not logged in
sessionInterface, _ := c.Get("session")
sessionID := sessionInterface.(string)
if session, err := sessionDao.GetSession(sessionID); err != nil || session.Username == "" {
c.Redirect(http.StatusTemporaryRedirect, "/")
//c.AbortWithStatus(http.StatusUnauthorized)
}
}
}
// EnsureAdminStatus ensures that a request will be aborted with an error
// if the user is not logged in
func EnsureAdminStatus() gin.HandlerFunc {
return func(c *gin.Context) {
// If there's an error or if the token is empty
// the user is not logged in
sessionInterface, _ := c.Get("session")
sessionID := sessionInterface.(string)
if session, err := sessionDao.GetSession(sessionID); err != nil || !session.IsAdmin {
c.Redirect(http.StatusTemporaryRedirect, "/")
//c.AbortWithStatus(http.StatusUnauthorized)
}
}
}
// EnsureNotLoggedIn ensures that a request will be aborted with an error
// if the user is already logged in
func EnsureNotLoggedIn() gin.HandlerFunc {
return func(c *gin.Context) {
// If there's no error or if the token is not empty
// the user is already logged in
sessionInterface, _ := c.Get("session")
sessionID := sessionInterface.(string)
if session, err := sessionDao.GetSession(sessionID); err != nil || session.Username != "" {
c.Redirect(http.StatusTemporaryRedirect, "/")
//c.AbortWithStatus(http.StatusUnauthorized)
}
}
}
// SetSessionStatus reads sessionId from cookie if available or create new session object
// and sets cookie accordingly.
func SetSessionStatus() gin.HandlerFunc {
return func(c *gin.Context) {
if sessionID, err := c.Cookie("session"); err == nil || sessionID != "" {
c.Set("session", sessionID)
} else {
session, _ := sessionDao.GetSession(bson.NewObjectId().Hex())
sessionID := session.ID.Hex()
c.Set("session", sessionID)
c.SetCookie("session", sessionID, 3600, "", "", false, true)
}
}
}
// SetSessionData populates session information with username, admin status of user and
// application version.
func SetSessionData(c *gin.Context, data gin.H) {
sessionInterface, _ := c.Get("session")
sessionID := sessionInterface.(string)
session, _ := sessionDao.GetSession(sessionID)
if gin.IsDebugging() {
log.Printf("setSessionData(%v): %v", sessionID, session)
}
data["is_logged_in"] = (session.Username != "")
data["is_admin"] = session.IsAdmin
data["version"] = properties.Version
}
+11
View File
@@ -0,0 +1,11 @@
package auth
import "gopkg.in/mgo.v2/bson"
// Session defines the data model for sessions with id,user name and admin status.
type Session struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Username string `json:"username" bson:"username,omitempty"`
IsAdmin bool `json:"is_admin" bson:"is_admin,omitempty"`
Model string `json:"model" bson:"model,omitempty"`
}
+78
View File
@@ -0,0 +1,78 @@
package auth
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// SessionDAO extends the type BaseDAO.
type SessionDAO struct {
Db dao.BaseDAO
}
const (
// SESSIONCOLLECTION defines the collection name for storing session data.
SESSIONCOLLECTION = "session"
// SESSIONMODEL defines the name of the session data model.
SESSIONMODEL = "kontor.admin.session"
)
// FindAll retrieves the list of sessions from the database.
func (m *SessionDAO) FindAll() ([]Session, error) {
m.Db.Connect()
var sessions []Session
err := m.Db.MongoDb.C(SESSIONCOLLECTION).Find(bson.M{"model": SESSIONMODEL}).All(&sessions)
return sessions, err
}
// FindByID returns a session with given id or returns the error.
func (m *SessionDAO) FindByID(id string) (Session, error) {
m.Db.Connect()
var session Session
err := m.Db.MongoDb.C(SESSIONCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&session)
return session, err
}
// Insert a session into database.
func (m *SessionDAO) Insert(session Session) error {
m.Db.Connect()
session.Model = SESSIONMODEL
err := m.Db.MongoDb.C(SESSIONCOLLECTION).Insert(&session)
//log.PrintDebug("Insert: %v, %v\n", session, err)
return err
}
// Upsert a session into database.
func (m *SessionDAO) Upsert(session Session) (*mgo.ChangeInfo, error) {
m.Db.Connect()
session.Model = SESSIONMODEL
info, err := m.Db.MongoDb.C(SESSIONCOLLECTION).Upsert(bson.M{"_id": session.ID}, &session)
return info, err
}
// Update an existing session.
func (m *SessionDAO) Update(session Session) error {
m.Db.Connect()
err := m.Db.MongoDb.C(SESSIONCOLLECTION).UpdateId(session.ID, &session)
return err
}
// Delete an existing session.
func (m *SessionDAO) Delete(session Session) error {
m.Db.Connect()
err := m.Db.MongoDb.C(SESSIONCOLLECTION).Remove(&session)
return err
}
// GetSession get a session by given id or create a new one, if nothing was found.
func (m *SessionDAO) GetSession(id string) (*Session, error) {
m.Db.Connect()
session, err := m.FindByID(id)
if err != nil {
session = Session{ID: bson.ObjectIdHex(id), Username: "", IsAdmin: false}
m.Insert(session)
}
return &session, nil
}
+103
View File
@@ -0,0 +1,103 @@
package auth
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var sessionModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Username", "string"},
{"IsAdmin", "bool"},
{"Model", "string"},
}
func TestSessionModel(t *testing.T) {
m := Session{}
if reflect.TypeOf(m).NumField() != len(sessionModelTestTable) {
t.Fail()
}
for index, testData := range sessionModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListSessions(t *testing.T) {
var (
sessionDao = SessionDAO{Db: dao.TestDb}
)
sessions, err := sessionDao.FindAll()
if err != nil {
t.Fail()
}
if sessions != nil {
t.Fail()
}
}
func TestInsertSession(t *testing.T) {
var (
sessionDao = SessionDAO{Db: dao.TestDb}
session = Session{}
sessions []Session
)
session.ID = bson.NewObjectId()
session.Username = "test"
err := sessionDao.Insert(session)
if err != nil {
t.Fail()
}
sessions, err = sessionDao.FindAll()
if err != nil {
t.Fail()
}
if len(sessions) != 1 {
t.Fail()
}
}
func TestUpsertSession(t *testing.T) {
var (
sessionDao = SessionDAO{Db: dao.TestDb}
session = Session{}
)
session.ID = bson.NewObjectId()
session.Username = "test2"
sessionDao.Upsert(session)
sessions, err := sessionDao.FindAll()
if err != nil {
t.Fail()
}
if len(sessions) != 2 {
t.Fail()
}
}
func TestDeleteSession(t *testing.T) {
var (
sessionDao = SessionDAO{Db: dao.TestDb}
)
sessions, err := sessionDao.FindAll()
if err != nil {
t.Fail()
}
for _, session := range sessions {
sessionDao.Delete(session)
}
sessions, err = sessionDao.FindAll()
if err != nil {
t.Fail()
}
if len(sessions) != 0 {
t.Fail()
}
}
+12
View File
@@ -0,0 +1,12 @@
package comics
import (
"gopkg.in/mgo.v2/bson"
)
// Artist defines the data model for comic artists with id and name.
type Artist struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Model string `json:"model" bson:"model"`
}
+78
View File
@@ -0,0 +1,78 @@
package comics
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"log"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// ArtistDAO extends the type BaseDAO.
type ArtistDAO struct {
Db dao.BaseDAO
}
const (
// ARTISTCOLLECTION defines the collection name for storing comic artists.
ARTISTCOLLECTION = "artist"
// ARTISTMODEL defines the name of the artist data model.
ARTISTMODEL = "kontor.comics.artist"
)
// FindAll retrieves the list of artists from the database.
func (m *ArtistDAO) FindAll() ([]Artist, error) {
m.Db.Connect()
var artists []Artist
err := m.Db.MongoDb.C(ARTISTCOLLECTION).Find(bson.M{"model": ARTISTMODEL}).All(&artists)
return artists, err
}
// FindByID returns an artists with given id or returns the error.
func (m *ArtistDAO) FindByID(id string) (Artist, error) {
m.Db.Connect()
var artist Artist
err := m.Db.MongoDb.C(ARTISTCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&artist)
return artist, err
}
// FindByName returns an artists with given name or returns the error.
func (m *ArtistDAO) FindByName(name string) (Artist, error) {
m.Db.Connect()
var artist Artist
err := m.Db.MongoDb.C(ARTISTCOLLECTION).Find(bson.M{"name": name, "model": ARTISTMODEL}).One(&artist)
return artist, err
}
// Insert an artist into database.
func (m *ArtistDAO) Insert(artist Artist) error {
m.Db.Connect()
artist.Model = ARTISTMODEL
err := m.Db.MongoDb.C(ARTISTCOLLECTION).Insert(&artist)
return err
}
// Upsert an artist into database.
func (m *ArtistDAO) Upsert(artist Artist) (*mgo.ChangeInfo, error) {
m.Db.Connect()
artist.Model = ARTISTMODEL
info, err := m.Db.MongoDb.C(ARTISTCOLLECTION).Upsert(bson.M{"name": artist.Name}, &artist)
return info, err
}
// Delete an existing artist.
func (m *ArtistDAO) Delete(artist Artist) error {
m.Db.Connect()
err := m.Db.MongoDb.C(ARTISTCOLLECTION).Remove(&artist)
if err != nil {
log.Printf("ArtistDao.Delete: %v", err)
}
return err
}
// Update an existing artist.
func (m *ArtistDAO) Update(artist Artist) error {
m.Db.Connect()
err := m.Db.MongoDb.C(ARTISTCOLLECTION).UpdateId(artist.ID, &artist)
return err
}
+96
View File
@@ -0,0 +1,96 @@
package comics
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var artistModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Name", "string"},
{"Model", "string"},
}
func TestArtistModel(t *testing.T) {
m := Artist{}
if reflect.TypeOf(m).NumField() != len(artistModelTestTable) {
t.Fail()
}
for index, testData := range artistModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListArtists(t *testing.T) {
var (
artistDao = ArtistDAO{Db: dao.TestDb}
)
artists, err := artistDao.FindAll()
if err != nil {
t.Fail()
}
if artists != nil {
t.Fail()
}
}
func TestInsertArtist(t *testing.T) {
var (
artistDao = ArtistDAO{Db: dao.TestDb}
artist = Artist{}
artists []Artist
)
artist.ID = bson.NewObjectId()
artist.Name = "Turner, Michael"
err := artistDao.Insert(artist)
if err != nil {
t.Fail()
}
artists, _ = artistDao.FindAll()
if len(artists) != 1 {
t.Fail()
}
}
func TestUpsertArtist(t *testing.T) {
var (
artistDao = ArtistDAO{Db: dao.TestDb}
artist = Artist{}
)
artist.ID = bson.NewObjectId()
artist.Name = "Marz, Ron"
_, err := artistDao.Upsert(artist)
if err != nil {
t.Fail()
}
artists, _ := artistDao.FindAll()
if len(artists) != 2 {
t.Fail()
}
}
func TestDeleteArtist(t *testing.T) {
var (
artistDao = ArtistDAO{Db: dao.TestDb}
)
artists, err := artistDao.FindAll()
if err != nil {
t.Fail()
}
for _, artist := range artists {
artistDao.Delete(artist)
}
artists, _ = artistDao.FindAll()
if len(artists) != 0 {
t.Fail()
}
}
+23
View File
@@ -0,0 +1,23 @@
package comics
import (
"net/http"
"github.com/gin-gonic/gin"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/util"
)
const (
// ArtistPublisherTemplate defines name of template file for comics publishers
ArtistPublisherTemplate = "comics/publishers.html"
)
func showArtistList(c *gin.Context) {
var dao = ArtistDAO{Db: dao.KontorDb}
if artists, err := dao.FindAll(); err == nil {
util.Render(c, gin.H{"title": "Comic Artists", "payload": artists}, "artists.html")
} else {
c.AbortWithError(http.StatusNotFound, err)
}
}
+15
View File
@@ -0,0 +1,15 @@
package comics
import (
"gopkg.in/mgo.v2/bson"
)
// Comic defines the data model for comic issues with id, title, publisher, order and completion status.
type Comic struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Title string `json:"title" bson:"title"`
Publisher bson.ObjectId `json:"publisher" bson:"publisher,omitempty"`
CurrentOrder bool `json:"current_order" bson:"current_order"`
Completed bool `json:"completed" bson:"completed"`
Model string `json:"model" bson:"model"`
}
+75
View File
@@ -0,0 +1,75 @@
package comics
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// ComicDAO extends the type BaseDAO.
type ComicDAO struct {
Db dao.BaseDAO
}
const (
// COMICCOLLECTION defines the collection name for storing comics.
COMICCOLLECTION = "comic"
// COMICMODEL defines the name of the comic data model.
COMICMODEL = "kontor.comics.comic"
)
// FindAll retrieves the list of comisc from the database.
func (m *ComicDAO) FindAll() ([]Comic, error) {
m.Db.Connect()
var comics []Comic
err := m.Db.MongoDb.C(COMICCOLLECTION).Find(bson.M{"model": COMICMODEL}).All(&comics)
return comics, err
}
// FindByID returns an comic with given id or returns the error.
func (m *ComicDAO) FindByID(id string) (Comic, error) {
m.Db.Connect()
var comic Comic
err := m.Db.MongoDb.C(COMICCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&comic)
return comic, err
}
// FindByName returns an comic with given name or returns the error.
func (m *ComicDAO) FindByName(name string) (Comic, error) {
m.Db.Connect()
var comic Comic
err := m.Db.MongoDb.C(COMICCOLLECTION).Find(bson.M{"name": name, "model": COMICMODEL}).One(&comic)
return comic, err
}
// Insert a comic into database.
func (m *ComicDAO) Insert(comic Comic) error {
m.Db.Connect()
comic.Model = COMICMODEL
err := m.Db.MongoDb.C(COMICCOLLECTION).Insert(&comic)
//util.PrintDebug("ComicDAO.Insert: %v", comic)
return err
}
// Upsert a comic into database.
func (m *ComicDAO) Upsert(comic Comic) (*mgo.ChangeInfo, error) {
m.Db.Connect()
comic.Model = COMICMODEL
info, err := m.Db.MongoDb.C(COMICCOLLECTION).Upsert(bson.M{"title": comic.Title}, &comic)
return info, err
}
// Delete an existing comic.
func (m *ComicDAO) Delete(comic Comic) error {
m.Db.Connect()
err := m.Db.MongoDb.C(COMICCOLLECTION).Remove(&comic)
return err
}
// Update an existing movie
func (m *ComicDAO) Update(comic Comic) error {
m.Db.Connect()
err := m.Db.MongoDb.C(COMICCOLLECTION).UpdateId(comic.ID, &comic)
return err
}
+88
View File
@@ -0,0 +1,88 @@
package comics
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var comicModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Title", "string"},
{"Publisher", "string"},
{"CurrentOrder", "bool"},
{"Completed", "bool"},
{"Model", "string"},
}
func TestComicModel(t *testing.T) {
m := Comic{}
if reflect.TypeOf(m).NumField() != len(comicModelTestTable) {
t.Fail()
}
for index, testData := range comicModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListComics(t *testing.T) {
var (
comicDao = ComicDAO{Db: dao.TestDb}
)
comics, err := comicDao.FindAll()
if err != nil {
t.Fail()
}
if len(comics) != 0 {
t.Fail()
}
}
func TestInsertComic(t *testing.T) {
var (
comicDao = ComicDAO{Db: dao.TestDb}
comic = Comic{}
comics []Comic
)
comic.ID = bson.NewObjectId()
comic.Title = "Simpsons"
comicDao.Insert(comic)
comics, _ = comicDao.FindAll()
if len(comics) != 1 {
t.Fail()
}
}
func TestUpsertComic(t *testing.T) {
var (
comicDao = ComicDAO{Db: dao.TestDb}
comic = Comic{}
)
comic.ID = bson.NewObjectId()
comic.Title = "1602"
comicDao.Upsert(comic)
comics, _ := comicDao.FindAll()
if len(comics) != 2 {
t.Fail()
}
}
func TestDeleteComic(t *testing.T) {
var (
comicDao = ComicDAO{Db: dao.TestDb}
)
comics, _ := comicDao.FindAll()
for _, comic := range comics {
comicDao.Delete(comic)
}
comics, _ = comicDao.FindAll()
if len(comics) != 0 {
t.Fail()
}
}
+12
View File
@@ -0,0 +1,12 @@
package comics
import (
"gopkg.in/mgo.v2/bson"
)
// Publisher defines the data model for comic publishers with id and name.
type Publisher struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Model string `json:"model" bson:"model"`
}
+75
View File
@@ -0,0 +1,75 @@
package comics
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// PublisherDAO extends the type BaseDAO.
type PublisherDAO struct {
Db dao.BaseDAO
}
const (
// PUBLISHERCOLLECTION defines the collection name for storing publishers.
PUBLISHERCOLLECTION = "publisher"
// PUBLISHERMODEL defines the name of the publisher data model.
PUBLISHERMODEL = "kontor.comics.publisher"
)
// FindAll retrieves the list of publishers from the database.
func (m *PublisherDAO) FindAll() ([]Publisher, error) {
m.Db.Connect()
var publishers []Publisher
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).Find(bson.M{"model": PUBLISHERMODEL}).All(&publishers)
return publishers, err
}
// FindByID returns an publisher with given id or returns the error.
func (m *PublisherDAO) FindByID(id string) (Publisher, error) {
m.Db.Connect()
var publisher Publisher
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&publisher)
return publisher, err
}
// FindByName returns an comic with given name or returns the error.
func (m *PublisherDAO) FindByName(name string) (Publisher, error) {
m.Db.Connect()
var publisher Publisher
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).Find(bson.M{"name": name, "model": PUBLISHERMODEL}).One(&publisher)
return publisher, err
}
// Insert a publisher into database.
func (m *PublisherDAO) Insert(publisher Publisher) error {
m.Db.Connect()
publisher.Model = PUBLISHERMODEL
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).Insert(&publisher)
//util.PrintDebug("PublisherDAO.Insert: %v", publisher)
return err
}
// Upsert a publisher into database.
func (m *PublisherDAO) Upsert(publisher Publisher) (*mgo.ChangeInfo, error) {
m.Db.Connect()
publisher.Model = PUBLISHERMODEL
info, err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).Upsert(bson.M{"name": publisher.Name}, &publisher)
return info, err
}
// Delete an existing publisher.
func (m *PublisherDAO) Delete(publisher Publisher) error {
m.Db.Connect()
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).Remove(&publisher)
return err
}
// Update an existing publisher.
func (m *PublisherDAO) Update(publisher Publisher) error {
m.Db.Connect()
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).UpdateId(publisher.ID, &publisher)
return err
}
+87
View File
@@ -0,0 +1,87 @@
package comics
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var publisherModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Name", "string"},
{"Model", "string"},
}
func TestPublisherModel(t *testing.T) {
m := Publisher{}
if reflect.TypeOf(m).NumField() != len(publisherModelTestTable) {
t.Fail()
}
for index, testData := range publisherModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListPublishers(t *testing.T) {
var (
publisherDao = PublisherDAO{Db: dao.TestDb}
)
publishers, err := publisherDao.FindAll()
if err != nil {
t.Fail()
}
if len(publishers) != 0 {
t.Fail()
}
}
func TestInsertPublisher(t *testing.T) {
var (
publisherDao = PublisherDAO{Db: dao.TestDb}
publisher = Publisher{}
publishers []Publisher
)
publisher.ID = bson.NewObjectId()
publisher.Name = "CrossGen"
publisherDao.Insert(publisher)
publishers, _ = publisherDao.FindAll()
if len(publishers) != 1 {
t.Fail()
}
}
func TestUpsertPublisher(t *testing.T) {
var (
publisherDao = PublisherDAO{Db: dao.TestDb}
publisher = Publisher{}
)
publisher.ID = bson.NewObjectId()
publisher.Name = "Marvel"
publisherDao.Upsert(publisher)
publishers, _ := publisherDao.FindAll()
if len(publishers) != 2 {
t.Fail()
}
}
func TestDeletePublisher(t *testing.T) {
var (
publisherDao = PublisherDAO{Db: dao.TestDb}
)
publishers, _ := publisherDao.FindAll()
for _, publisher := range publishers {
publisherDao.Delete(publisher)
}
publishers, _ = publisherDao.FindAll()
if len(publishers) != 0 {
t.Fail()
}
}
+70
View File
@@ -0,0 +1,70 @@
package comics
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/util"
"net/http"
"github.com/gin-gonic/gin"
)
const (
// ComicsPublisherTemplate defines name of template file for comics publishers
ComicsPublisherTemplate = "comics/publishers.html"
// ComicsPublisherDetailsTemplate defines name of template file for comics publishers
ComicsPublisherDetailsTemplate = "comics/publisher.html"
)
func showPublisherList(c *gin.Context) {
var dao = PublisherDAO{Db: dao.KontorDb}
if publishers, err := dao.FindAll(); err == nil {
util.Render(c, gin.H{"title": "Comics Publisher List", "payload": publishers}, ComicsPublisherTemplate)
} else {
c.AbortWithError(http.StatusNotFound, err)
}
}
func showPublisherDetails(c *gin.Context) {
var dao = PublisherDAO{Db: dao.KontorDb}
publisherid := c.Param("publisher_id")
if publisher, err := dao.FindByID(publisherid); err == nil {
util.Render(c, gin.H{"title": "Comics Publisher", "payload": publisher, "action": util.SaveAction}, ComicsPublisherDetailsTemplate)
} else {
c.AbortWithError(http.StatusNotFound, err)
}
}
func showPublisherCreation(c *gin.Context) {
var publisher = Publisher{}
util.Render(c, gin.H{"title": "Comics Publisher Creation", "payload": publisher, "action": util.AddAction}, ComicsPublisherTemplate)
}
func validatePublisherDetails(c *gin.Context) {
name := c.PostForm("name")
action := c.PostForm("action")
publisherid := c.PostForm("publisherid")
var err error
var dao = PublisherDAO{Db: dao.KontorDb}
var publisher = Publisher{}
switch action {
case util.AddAction:
publisher.Name = name
_, err = dao.Upsert(publisher)
case util.SaveAction:
publisher, _ = dao.FindByID(publisherid)
publisher.Name = name
err = dao.Update(publisher)
case util.DeleteAction:
publisher, _ = dao.FindByID(publisherid)
err = dao.Delete(publisher)
}
if err == nil {
c.Redirect(http.StatusTemporaryRedirect, "/comics/publisher")
} else {
c.HTML(http.StatusBadRequest, "comics/publisher.html", gin.H{
"ErrorTitle": "Publisher Creation Failed",
"ErrorMessage": err.Error()})
}
}
+28
View File
@@ -0,0 +1,28 @@
package comics
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/auth"
"github.com/gin-gonic/gin"
)
// GetRoutes returns all routes for comic related data.
func GetRoutes(router *gin.Engine) {
comicRoutes := router.Group("/comics")
{
comicRoutes.GET("/", auth.EnsureLoggedIn(), showComicList)
comicRoutes.GET("/artist", auth.EnsureLoggedIn(), showArtistList)
comicRoutes.GET("/artist/view/:artist_id", auth.EnsureLoggedIn(), showArtistList)
comicRoutes.GET("/artist/create", auth.EnsureLoggedIn(), showArtistList)
comicRoutes.POST("/artist/create", auth.EnsureLoggedIn(), showArtistList)
comicRoutes.GET("/comic", auth.EnsureLoggedIn(), showComicList)
comicRoutes.GET("/comic/view/:comic_id", auth.EnsureLoggedIn(), showComic)
comicRoutes.GET("/comic/create", auth.EnsureLoggedIn(), showComicList)
comicRoutes.POST("/comic/create", auth.EnsureLoggedIn(), showComicList)
comicRoutes.GET("/publisher", auth.EnsureLoggedIn(), showPublisherList)
comicRoutes.POST("/publisher", auth.EnsureLoggedIn(), showPublisherList)
comicRoutes.GET("/publisher/view/:publisher_id", auth.EnsureLoggedIn(), showPublisherDetails)
comicRoutes.POST("/publisher/validate", auth.EnsureLoggedIn(), validatePublisherDetails)
comicRoutes.GET("/publisher/create", auth.EnsureLoggedIn(), showPublisherCreation)
}
}
+28
View File
@@ -0,0 +1,28 @@
package comics
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/util"
"net/http"
"github.com/gin-gonic/gin"
)
func showComicList(c *gin.Context) {
var dao = ComicDAO{Db: dao.KontorDb}
if comics, err := dao.FindAll(); err == nil {
util.Render(c, gin.H{"title": "Comics", "payload": comics}, "comics.html")
} else {
c.AbortWithError(http.StatusNotFound, err)
}
}
func showComic(c *gin.Context) {
var dao = ComicDAO{Db: dao.KontorDb}
comicID := c.Param("comic_id")
if comic, err := dao.FindByID(comicID); err == nil {
util.Render(c, gin.H{"title": "Comic Details", "payload": comic, "action": util.SaveAction}, "comic.html")
} else {
c.AbortWithError(http.StatusNotFound, err)
}
}
+15
View File
@@ -0,0 +1,15 @@
package responses
// Response is the Ping Response
type Response struct {
Message string `json:"message"`
}
type ComicList struct {
Comics []Comic `json:"comics"`
}
type Comic struct {
ID string `json:"id"`
Title string `json:"title"`
}
+33
View File
@@ -0,0 +1,33 @@
package routing
import (
"net/http"
"gitlab.com/tpeetz-kontor/kontor-go/cmd/pkg/context/comic/responses"
"gitlab.com/tpeetz-kontor/kontor-go/cmd/pkg/infrastructure/app"
responseFactory "gitlab.com/tpeetz-kontor/kontor-go/cmd/pkg/infrastructure/response"
)
// Handler is the http.Handler for this request
type Handler struct {
app *app.Application
}
// NewHandler will create a new Handler to handle this request
func NewHandler(app *app.Application) *Handler {
return &Handler{app}
}
// Handle will handle the incoming request
func (handler *Handler) ComicList(response http.ResponseWriter, request *http.Request) {
handler.app.Logger.Info("Ping Handler Dispatched.")
responseFactory.Send(
response,
http.StatusOK,
&responses.ComicList{
Comics: []responses.Comic{{ID: "123", Title: "Comic1"}, {ID: "123", Title: "Comic1"}},
},
handler.app.Config.HTTP.Content,
)
}
+31
View File
@@ -0,0 +1,31 @@
package dao
import (
"log"
mgo "gopkg.in/mgo.v2"
)
// BaseDAO definess the connection parameters to a MongoDB instance.
type BaseDAO struct {
Server string
Database string
MongoDb *mgo.Database
}
var (
// KontorDb has the database connection to the productive MongoDB instance.
KontorDb = BaseDAO{Server: "localhost", Database: "kontor"}
// TestDb has the database connection to the test MongoDB instance.
TestDb = BaseDAO{Server: "localhost", Database: "kontor_test"}
)
// Connect instantiates the database session.
func (m *BaseDAO) Connect() {
session, err := mgo.Dial(m.Server)
if err != nil {
//util.PrintDebug("Connect: %v", err)
log.Fatal(err)
}
m.MongoDb = session.DB(m.Database)
}
+51
View File
@@ -0,0 +1,51 @@
package dao
import (
"reflect"
"testing"
)
var baseDaoTestTable = []struct {
name string
typeName string
}{
{"Server", "string"},
{"Database", "string"},
{"MongoDb", "ptr"},
}
func TestCheckBaseDao(t *testing.T) {
d := BaseDAO{}
for index, testData := range baseDaoTestTable {
givenType := reflect.TypeOf(d).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestConnectDb(t *testing.T) {
d := BaseDAO{}
d.Connect()
if d.MongoDb == nil {
t.Fail()
}
}
func TestDatabasesConfig(t *testing.T) {
kontorDb := KontorDb
if kontorDb.Server != "localhost" {
t.Fail()
}
if kontorDb.Database != "kontor" {
t.Fail()
}
testDb := TestDb
if testDb.Server != "localhost" {
t.Fail()
}
if testDb.Database != "kontor_test" {
t.Fail()
}
}
+50
View File
@@ -0,0 +1,50 @@
package app
import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gorilla/mux"
"gitlab.com/tpeetz-kontor/kontor-go/pkg/infrastructure/config"
"go.uber.org/zap"
)
// Application is our general purpose Application struct
type Application struct {
Server *http.Server
Router *mux.Router
Logger *zap.Logger
Config *config.Config
}
// Run will run the Application server
func (app *Application) Run() {
app.Logger.Info("App started...")
err := app.Server.ListenAndServe()
if err != nil {
fmt.Println(err)
}
}
// WaitForShutdown is a graceful way to handle server shutdown events
func WaitForShutdown(application *Application) {
// Create a channel to listen for OS signals
interruptChan := make(chan os.Signal, 1)
signal.Notify(interruptChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
// Block until we receive a signal to our channel
<-interruptChan
application.Logger.Info("Received shutdown signal, gracefully terminating")
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
application.Server.Shutdown(ctx)
os.Exit(0)
}
+48
View File
@@ -0,0 +1,48 @@
package config
import "os"
// AppConfig is the Application configuration struct
type AppConfig struct {
Name string
Version string
Token string
}
// HTTPConfig is the Application HTTP configuration
type HTTPConfig struct {
Content string
Problem string
Port string
}
// Config is the Configuration struct
type Config struct {
App AppConfig
HTTP HTTPConfig
}
// New returns a new Config Struct
func New() *Config {
return &Config{
App: AppConfig{
Name: env("APP_NAME", "Kontor"),
Version: env("APP_VERSION", "v1.0"),
Token: env("APP_TOKEN", ""),
},
HTTP: HTTPConfig{
Content: env("HTTP_CONTENT_TYPE", "application/json"),
Problem: env("HTTP_PROBLEM", "application/problem+json"),
Port: env("HTTP_PORT", ":8086"),
},
}
}
// env is a simple helper function to read an environment variable or return a default value
func env(key string, defaultValue string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return defaultValue
}
+91
View File
@@ -0,0 +1,91 @@
package kernel
import (
"context"
"net/http"
"time"
"github.com/google/uuid"
gohandlers "github.com/gorilla/handlers"
"github.com/gorilla/mux"
"gitlab.com/tpeetz-kontor/kontor-go/pkg/infrastructure/app"
"gitlab.com/tpeetz-kontor/kontor-go/pkg/infrastructure/config"
"go.uber.org/zap"
)
// Boot the Application
func Boot() *app.Application {
// Configuration
config := bootConfig()
// Router
router := bootRouter()
// CORS
corsHandler := gohandlers.CORS(gohandlers.AllowedOrigins([]string{"*"}))
// Logger
logger := bootLogger()
defer logger.Sync() // flushes buffer, if any
// Create and return and Application
return &app.Application{
Server: &http.Server{
Addr: config.HTTP.Port,
Handler: corsHandler(requestIDMiddleware(router)),
IdleTimeout: 120 * time.Second,
ReadTimeout: 1 * time.Second,
WriteTimeout: 1 * time.Second,
},
Router: router,
Logger: logger,
Config: config,
}
}
func bootConfig() *config.Config {
return config.New()
}
func bootRouter() *mux.Router {
return mux.NewRouter()
}
func bootLogger() *zap.Logger {
logger, logError := zap.NewProduction()
if logError != nil {
panic(logError)
}
return logger
}
// ContextKey is used for context.Context value. The value requires a key that is not primitive type.
type ContextKey string
// ContextKeyRequestID is the ContextKey for RequestID
const ContextKeyRequestID ContextKey = "requestID"
func requestIDMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
id := uuid.New()
ctx = context.WithValue(ctx, ContextKeyRequestID, id.String())
r = r.WithContext(ctx)
bootLogger().Debug("Incoming request",
zap.String("method", r.Method),
zap.String("uri", r.RequestURI),
zap.String("addr", r.RemoteAddr), zap.String("id", id.String()),
)
next.ServeHTTP(w, r)
bootLogger().Debug("Finished handling http req. %s",
zap.String("id", id.String()))
})
}
@@ -0,0 +1,20 @@
package response
import (
"encoding/json"
"net/http"
)
// Response is a generic HTTP Response Struct
type Response struct {
Data string `json:"data"`
}
// Send a HTTP Response
func Send(responseWriter http.ResponseWriter, code int, payload interface{}, contentType string) {
response, _ := json.Marshal(payload)
responseWriter.Header().Set("Content-Type", contentType)
responseWriter.WriteHeader(code)
responseWriter.Write(response)
}
+12
View File
@@ -0,0 +1,12 @@
package library
import (
"gopkg.in/mgo.v2/bson"
)
// Author defines the data model for library authors with id and name.
type Author struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Model string `json:"model" bson:"model,omitempty"`
}
+74
View File
@@ -0,0 +1,74 @@
package library
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// AuthorDAO extends the type BaseDAO.
type AuthorDAO struct {
Db dao.BaseDAO
}
const (
// AUTHORCOLLECTION defines the collection name for storing authors.
AUTHORCOLLECTION = "author"
// AUTHORMODEL defines the name of the author data model.
AUTHORMODEL = "kontor.library.author"
)
// FindAll retrieves the list of authors from the database.
func (m *AuthorDAO) FindAll() ([]Author, error) {
m.Db.Connect()
var authors []Author
err := m.Db.MongoDb.C(AUTHORCOLLECTION).Find(bson.M{"model": AUTHORMODEL}).All(&authors)
return authors, err
}
// FindByID returns an author with given id or returns the error.
func (m *AuthorDAO) FindByID(id string) (Author, error) {
m.Db.Connect()
var author Author
err := m.Db.MongoDb.C(AUTHORCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&author)
return author, err
}
// FindByName returns an author with given name or returns the error.
func (m *AuthorDAO) FindByName(name string) (Author, error) {
m.Db.Connect()
var author Author
err := m.Db.MongoDb.C(AUTHORCOLLECTION).Find(bson.M{"name": name, "model": AUTHORMODEL}).One(&author)
return author, err
}
// Insert a author into database.
func (m *AuthorDAO) Insert(author Author) error {
m.Db.Connect()
author.Model = AUTHORMODEL
err := m.Db.MongoDb.C(AUTHORCOLLECTION).Insert(&author)
return err
}
// Upsert a author into database.
func (m *AuthorDAO) Upsert(author Author) (*mgo.ChangeInfo, error) {
m.Db.Connect()
author.Model = AUTHORMODEL
info, err := m.Db.MongoDb.C(AUTHORCOLLECTION).Upsert(bson.M{"name": author.Name}, &author)
return info, err
}
// Delete an existing author.
func (m *AuthorDAO) Delete(author Author) error {
m.Db.Connect()
err := m.Db.MongoDb.C(AUTHORCOLLECTION).Remove(&author)
return err
}
// Update an existing author.
func (m *AuthorDAO) Update(author Author) error {
m.Db.Connect()
err := m.Db.MongoDb.C(AUTHORCOLLECTION).UpdateId(author.ID, &author)
return err
}
+99
View File
@@ -0,0 +1,99 @@
package library
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var authorModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Name", "string"},
{"Model", "string"},
}
func TestAuthorModel(t *testing.T) {
m := Author{}
if reflect.TypeOf(m).NumField() != len(authorModelTestTable) {
t.Fail()
}
for index, testData := range authorModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListAuthors(t *testing.T) {
var (
authorDao = AuthorDAO{Db: dao.TestDb}
)
authors, err := authorDao.FindAll()
if err != nil {
t.Fail()
}
if len(authors) != 0 {
t.Fail()
}
}
func TestInsertAuthor(t *testing.T) {
var (
authorDao = AuthorDAO{Db: dao.TestDb}
author = Author{}
authors []Author
)
author.ID = bson.NewObjectId()
author.Name = "Packt Publishing"
err := authorDao.Insert(author)
if err != nil {
t.Fail()
}
authors, err = authorDao.FindAll()
if len(authors) != 1 {
t.Fail()
}
}
func TestUpsertAuthor(t *testing.T) {
var (
authorDao = AuthorDAO{Db: dao.TestDb}
)
var author = Author{}
author.ID = bson.NewObjectId()
author.Name = "Hansa Verlag"
authorDao.Upsert(author)
authors, err := authorDao.FindAll()
if err != nil {
t.Fail()
}
if len(authors) != 2 {
t.Fail()
}
}
func TestDeleteAuthor(t *testing.T) {
var (
authorDao = AuthorDAO{Db: dao.TestDb}
)
authors, err := authorDao.FindAll()
if err != nil {
t.Fail()
}
for _, author := range authors {
authorDao.Delete(author)
}
authors, err = authorDao.FindAll()
if err != nil {
t.Fail()
}
if len(authors) != 0 {
t.Fail()
}
}
+18
View File
@@ -0,0 +1,18 @@
package library
import (
"gopkg.in/mgo.v2/bson"
)
// Book defines the data model for library books with id, title, author, publisher,
// isbn, year and edition.
type Book struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Title string `json:"title" bson:"title"`
Author string `json:"author" bson:"author"`
Publisher bson.ObjectId `json:"publisher" bson:"publisher,omitempty"`
Isbn string `json:"isbn" bson:"isbn,omitempty"`
Year int `json:"year" bson:"year,omitempty"`
Edition string `json:"edition" bson:"edition,omitempty"`
Model string `json:"model" bson:"model,omitempty"`
}
+74
View File
@@ -0,0 +1,74 @@
package library
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// BookDAO extends the type BaseDAO.
type BookDAO struct {
Db dao.BaseDAO
}
const (
// BOOKCOLLECTION defines the collection name for storing books.
BOOKCOLLECTION = "book"
// BOOKMODEL defines the name of the book data model.
BOOKMODEL = "kontor.library.book"
)
// FindAll retrieves the list of books from the database.
func (m *BookDAO) FindAll() ([]Book, error) {
m.Db.Connect()
var books []Book
err := m.Db.MongoDb.C(BOOKCOLLECTION).Find(bson.M{"model": BOOKMODEL}).All(&books)
return books, err
}
// FindByID returns an book with given id or returns the error.
func (m *BookDAO) FindByID(id string) (Book, error) {
m.Db.Connect()
var book Book
err := m.Db.MongoDb.C(BOOKCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&book)
return book, err
}
// FindByTitle returns a book with given title or returns the error.
func (m *BookDAO) FindByTitle(title string) (Book, error) {
m.Db.Connect()
var book Book
err := m.Db.MongoDb.C(BOOKCOLLECTION).Find(bson.M{"title": title, "model": BOOKMODEL}).One(&book)
return book, err
}
// Insert a book into database.
func (m *BookDAO) Insert(book Book) error {
m.Db.Connect()
book.Model = BOOKMODEL
err := m.Db.MongoDb.C(BOOKCOLLECTION).Insert(&book)
return err
}
// Upsert a book into database.
func (m *BookDAO) Upsert(book Book) (*mgo.ChangeInfo, error) {
m.Db.Connect()
book.Model = BOOKMODEL
info, err := m.Db.MongoDb.C(BOOKCOLLECTION).Upsert(bson.M{"title": book.Title}, &book)
return info, err
}
// Delete an existing book.
func (m *BookDAO) Delete(book Book) error {
m.Db.Connect()
err := m.Db.MongoDb.C(BOOKCOLLECTION).Remove(&book)
return err
}
// Update an existing book.
func (m *BookDAO) Update(book Book) error {
m.Db.Connect()
err := m.Db.MongoDb.C(BOOKCOLLECTION).UpdateId(book.ID, &book)
return err
}
+107
View File
@@ -0,0 +1,107 @@
package library
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var bookModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Title", "string"},
{"Author", "string"},
{"Publisher", "string"},
{"Isbn", "string"},
{"Year", "int"},
{"Edition", "string"},
{"Model", "string"},
}
func TestBookModel(t *testing.T) {
m := Book{}
if reflect.TypeOf(m).NumField() != len(bookModelTestTable) {
t.Fail()
}
for index, testData := range bookModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListBooks(t *testing.T) {
var (
bookDao = BookDAO{Db: dao.TestDb}
)
books, err := bookDao.FindAll()
if err != nil {
t.Fail()
}
if len(books) != 0 {
t.Fail()
}
}
func TestInsertBook(t *testing.T) {
var (
bookDao = BookDAO{Db: dao.TestDb}
book = Book{}
books []Book
)
book.ID = bson.NewObjectId()
book.Title = "Packt Publishing"
err := bookDao.Insert(book)
if err != nil {
t.Fail()
}
books, err = bookDao.FindAll()
if err != nil {
t.Fail()
}
if len(books) != 1 {
t.Fail()
}
}
func TestUpsertBook(t *testing.T) {
var (
bookDao = BookDAO{Db: dao.TestDb}
book = Book{}
)
book.ID = bson.NewObjectId()
book.Title = "Hansa Verlag"
bookDao.Upsert(book)
books, err := bookDao.FindAll()
if err != nil {
t.Fail()
}
if len(books) != 2 {
t.Fail()
}
}
func TestDeleteBook(t *testing.T) {
var (
bookDao = BookDAO{Db: dao.TestDb}
)
books, err := bookDao.FindAll()
if err != nil {
t.Fail()
}
for _, book := range books {
bookDao.Delete(book)
}
books, err = bookDao.FindAll()
if err != nil {
t.Fail()
}
if len(books) != 0 {
t.Fail()
}
}
+12
View File
@@ -0,0 +1,12 @@
package library
import (
"gopkg.in/mgo.v2/bson"
)
// Publisher defines the data model for library publishers with id and name.
type Publisher struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Model string `json:"model" bson:"model"`
}
+74
View File
@@ -0,0 +1,74 @@
package library
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// PublisherDAO extends the type BaseDAO.
type PublisherDAO struct {
Db dao.BaseDAO
}
const (
// PUBLISHERCOLLECTION defines the collection name for storing publishers.
PUBLISHERCOLLECTION = "publisher"
// PUBLISHERMODEL defines the name of the publisher data model.
PUBLISHERMODEL = "kontor.library.publisher"
)
// FindAll retrieves the list of publishers from the database.
func (m *PublisherDAO) FindAll() ([]Publisher, error) {
m.Db.Connect()
var publishers []Publisher
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).Find(bson.M{"model": PUBLISHERMODEL}).All(&publishers)
return publishers, err
}
// FindByID returns an publisher with given id or returns the error.
func (m *PublisherDAO) FindByID(id string) (Publisher, error) {
m.Db.Connect()
var publisher Publisher
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&publisher)
return publisher, err
}
// FindByName returns an comic with given name or returns the error.
func (m *PublisherDAO) FindByName(name string) (Publisher, error) {
m.Db.Connect()
var publisher Publisher
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).Find(bson.M{"name": name, "model": PUBLISHERMODEL}).One(&publisher)
return publisher, err
}
// Insert a publisher into database.
func (m *PublisherDAO) Insert(publisher Publisher) error {
m.Db.Connect()
publisher.Model = PUBLISHERMODEL
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).Insert(&publisher)
return err
}
// Upsert a publisher into database.
func (m *PublisherDAO) Upsert(publisher Publisher) (*mgo.ChangeInfo, error) {
m.Db.Connect()
publisher.Model = PUBLISHERMODEL
info, err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).Upsert(bson.M{"name": publisher.Name}, &publisher)
return info, err
}
// Delete an existing publisher.
func (m *PublisherDAO) Delete(publisher Publisher) error {
m.Db.Connect()
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).Remove(&publisher)
return err
}
// Update an existing publisher.
func (m *PublisherDAO) Update(publisher Publisher) error {
m.Db.Connect()
err := m.Db.MongoDb.C(PUBLISHERCOLLECTION).UpdateId(publisher.ID, &publisher)
return err
}
+103
View File
@@ -0,0 +1,103 @@
package library
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var publisherModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Name", "string"},
{"Model", "string"},
}
func TestPublisherModel(t *testing.T) {
m := Publisher{}
if reflect.TypeOf(m).NumField() != len(publisherModelTestTable) {
t.Fail()
}
for index, testData := range publisherModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListPublishers(t *testing.T) {
var (
publisherDao = PublisherDAO{Db: dao.TestDb}
)
publishers, err := publisherDao.FindAll()
if err != nil {
t.Fail()
}
if len(publishers) != 0 {
t.Fail()
}
}
func TestInsertPublisher(t *testing.T) {
var (
publisherDao = PublisherDAO{Db: dao.TestDb}
publisher = Publisher{}
publishers []Publisher
)
publisher.ID = bson.NewObjectId()
publisher.Name = "Packt Publishing"
err := publisherDao.Insert(publisher)
if err != nil {
t.Fail()
}
publishers, err = publisherDao.FindAll()
if err != nil {
t.Fail()
}
if len(publishers) != 1 {
t.Fail()
}
}
func TestUpsertPublisher(t *testing.T) {
var (
publisherDao = PublisherDAO{Db: dao.TestDb}
publisher = Publisher{}
)
publisher.ID = bson.NewObjectId()
publisher.Name = "Hansa Verlag"
publisherDao.Upsert(publisher)
publishers, err := publisherDao.FindAll()
if err != nil {
t.Fail()
}
if len(publishers) != 2 {
t.Fail()
}
}
func TestDeletePublisher(t *testing.T) {
var (
publisherDao = PublisherDAO{Db: dao.TestDb}
)
publishers, err := publisherDao.FindAll()
if err != nil {
t.Fail()
}
for _, publisher := range publishers {
publisherDao.Delete(publisher)
}
publishers, err = publisherDao.FindAll()
if err != nil {
t.Fail()
}
if len(publishers) != 0 {
t.Fail()
}
}
+68
View File
@@ -0,0 +1,68 @@
package library
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/util"
"net/http"
"github.com/gin-gonic/gin"
)
const (
// LibraryPublisherTemplate defines name of template file for comics publishers
LibraryPublisherTemplate = "library/publishers.html"
)
func showPublisherList(c *gin.Context) {
var dao = PublisherDAO{Db: dao.KontorDb}
if publishers, err := dao.FindAll(); err == nil {
util.Render(c, gin.H{"title": "Library Publisher List", "payload": publishers}, LibraryPublisherTemplate)
} else {
c.AbortWithError(http.StatusNotFound, err)
}
}
func showPublisherDetails(c *gin.Context) {
var dao = PublisherDAO{Db: dao.KontorDb}
publisherid := c.Param("publisher_id")
if publisher, err := dao.FindByID(publisherid); err == nil {
util.Render(c, gin.H{"title": "Library Publisher", "payload": publisher, "action": util.SaveAction}, LibraryPublisherTemplate)
} else {
c.AbortWithError(http.StatusNotFound, err)
}
}
func showPublisherCreation(c *gin.Context) {
var publisher = Publisher{}
util.Render(c, gin.H{"title": "Library Publisher Creation", "payload": publisher, "action": util.AddAction}, LibraryPublisherTemplate)
}
func validatePublisherDetails(c *gin.Context) {
name := c.PostForm("name")
action := c.PostForm("action")
publisherid := c.PostForm("publisherid")
var err error
var dao = PublisherDAO{Db: dao.KontorDb}
var publisher = Publisher{}
switch action {
case util.AddAction:
publisher.Name = name
_, err = dao.Upsert(publisher)
case util.SaveAction:
publisher, _ = dao.FindByID(publisherid)
publisher.Name = name
err = dao.Update(publisher)
case util.DeleteAction:
publisher, _ = dao.FindByID(publisherid)
err = dao.Delete(publisher)
}
if err == nil {
c.Redirect(http.StatusTemporaryRedirect, "/library/publisher")
} else {
c.HTML(http.StatusBadRequest, "library/publisher.html", gin.H{
"ErrorTitle": "Publisher Creation Failed",
"ErrorMessage": err.Error()})
}
}
+22
View File
@@ -0,0 +1,22 @@
package library
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/auth"
"github.com/gin-gonic/gin"
)
// GetRoutes returns all routes for library related data.
func GetRoutes(router *gin.Engine) {
libraryRoutes := router.Group("/library")
{
libraryRoutes.GET("/", auth.EnsureLoggedIn(), showBookList)
libraryRoutes.GET("/book", auth.EnsureLoggedIn(), showBookList)
libraryRoutes.GET("/author", auth.EnsureLoggedIn(), showAuthorList)
libraryRoutes.GET("/publisher", auth.EnsureLoggedIn(), showPublisherList)
libraryRoutes.POST("/publisher", auth.EnsureLoggedIn(), showPublisherList)
libraryRoutes.GET("/publisher/view/:publisher_id", auth.EnsureLoggedIn(), showPublisherDetails)
libraryRoutes.POST("/publisher/validate", auth.EnsureLoggedIn(), validatePublisherDetails)
libraryRoutes.GET("/publisher/create", auth.EnsureLoggedIn(), showPublisherCreation)
}
}
+24
View File
@@ -0,0 +1,24 @@
package library
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/util"
"github.com/gin-gonic/gin"
)
func showAuthorList(c *gin.Context) {
var authorDao = AuthorDAO{Db: dao.KontorDb}
if authors, err := authorDao.FindAll(); err == nil {
util.Render(c, gin.H{"title": "Author List", "payload": authors}, "library/authors.html")
}
}
func showBookList(c *gin.Context) {
var bookDao = BookDAO{Db: dao.KontorDb}
if books, err := bookDao.FindAll(); err == nil {
util.Render(c, gin.H{"title": "Book List", "payload": books}, "library/books.html")
} else {
util.Render(c, gin.H{"title": "Kontor", "payload": nil}, "kontor/index.html")
}
}
+13
View File
@@ -0,0 +1,13 @@
package office
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/auth"
"github.com/gin-gonic/gin"
)
// GetRoutes returns all routes for office related data.
func GetRoutes(router *gin.Engine) {
officeRoutes := router.Group("/office")
officeRoutes.GET("/", auth.EnsureLoggedIn(), showIndexPage)
}
+11
View File
@@ -0,0 +1,11 @@
package office
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/util"
"github.com/gin-gonic/gin"
)
func showIndexPage(c *gin.Context) {
util.Render(c, gin.H{"title": "Home Office", "payload": nil}, "office/index.html")
}
+25
View File
@@ -0,0 +1,25 @@
package properties
var (
// Version defines the version of the web application kontor.
Version = "undefined"
// Debug defines the property debug to be used for more verbose output.
Debug = false
// Port defines port number under the web application is reachable.
Port = 8500
)
// SetVersion sets Version with given value.
func SetVersion(value string) {
Version = value
}
// SetDebug sets Debug with given value.
func SetDebug(value bool) {
Debug = value
}
// SetPort sets Port with given value.
func SetPort(value int) {
Port = value
}
+20
View File
@@ -0,0 +1,20 @@
package setup
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/tysc"
"log"
)
// CheckTradeYourSportsCardsData checks if the TYSC releated data is available.
func CheckTradeYourSportsCardsData() {
log.Printf("Check data for TradeYourSportsCards module")
var sport = tysc.SportDAO{Db: dao.KontorDb}
sport.Upsert(tysc.Sport{Name: "Football"})
football, _ := sport.FindByName("Football")
sport.Upsert(tysc.Sport{Name: "Baseball"})
sport.Upsert(tysc.Sport{Name: "Basketball"})
sport.Upsert(tysc.Sport{Name: "Hockey"})
var position = tysc.PositionDAO{Db: dao.KontorDb}
position.Upsert(tysc.Position{Name: "WR", Description: "Wide Receiver", Sport: football.ID})
}
+38
View File
@@ -0,0 +1,38 @@
package setup
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/admin"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/auth"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/comics"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/library"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/office"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/tradingcards"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/tysc"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/util"
"github.com/gin-gonic/gin"
)
// InitializeRoutes setup the routes for Kontor web application.
func InitializeRoutes(router *gin.Engine) {
// Use the setUserStatus middleware for every route to set a flag
// indicating whether the request was from an authenticated user or not
router.Use(auth.SetSessionStatus())
// Handle the index route
router.GET("/", util.ShowIndexPage)
userRoutes := router.Group("/user")
{
userRoutes.GET("/login", auth.EnsureNotLoggedIn(), admin.ShowLoginPage)
userRoutes.POST("/login", auth.EnsureNotLoggedIn(), admin.PerformLogin)
userRoutes.GET("/logout", auth.EnsureLoggedIn(), admin.Logout)
}
admin.GetRoutes(router)
comics.GetRoutes(router)
library.GetRoutes(router)
office.GetRoutes(router)
tradingcards.GetRoutes(router)
tysc.GetRoutes(router)
}
+15
View File
@@ -0,0 +1,15 @@
package setup
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/auth"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
)
// CleanupSessions removes all sessions from database.
func CleanupSessions() {
sessionDao := auth.SessionDAO{Db: dao.KontorDb}
sessions, _ := sessionDao.FindAll()
for _, session := range sessions {
sessionDao.Delete(session)
}
}
+20
View File
@@ -0,0 +1,20 @@
package setup
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/admin"
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"gopkg.in/mgo.v2/bson"
)
// CheckUserList ensures that at least the admin user is available.
func CheckUserList() {
var userDao = admin.UserDAO{Db: dao.KontorDb}
users, err := userDao.FindAll()
if err == nil && len(users) == 0 {
password, _ := admin.HashPassword("admin")
id := bson.NewObjectId()
user := admin.User{ID: id, Username: "admin", Password: password, Firstname: "Administrator", IsAdmin: true}
userDao.Insert(user)
}
}
+13
View File
@@ -0,0 +1,13 @@
package tradingcards
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/auth"
"github.com/gin-gonic/gin"
)
// GetRoutes returns all routes for tradingcards related data.
func GetRoutes(router *gin.Engine) {
tradingCardsRoutes := router.Group("/tradingcards")
tradingCardsRoutes.GET("/", auth.EnsureLoggedIn(), showIndexPage)
}
+11
View File
@@ -0,0 +1,11 @@
package tradingcards
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/util"
"github.com/gin-gonic/gin"
)
func showIndexPage(c *gin.Context) {
util.Render(c, gin.H{"title": "Trading Cards", "payload": nil}, "tradingcards/index.html")
}
+20
View File
@@ -0,0 +1,20 @@
package tysc
import (
"gopkg.in/mgo.v2/bson"
)
// Card defines the data model for TYSC cards.
type Card struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Player bson.ObjectId `json:"player" bson:"player,omitempty"`
Team bson.ObjectId `json:"team" bson:"team,omitempty"`
Manufacturer bson.ObjectId `json:"manufacturer" bson:"manufacturer,omitempty"`
CardSet bson.ObjectId `json:"cardset" bson:"cardset,omitempty"`
ParallelSet bson.ObjectId `json:"parallelset" bson:"paralelset,omitempty"`
InsertSet bson.ObjectId `json:"insertset" bson:"insertset,omitempty"`
Rookie bool `json:"rookie" bson:"rookie,omitempty"`
Year int `json:"year" bson:"year,omitempty"`
Number int `json:"number" bson:"number,omitempty"`
Model string `json:"model" bson:"model,omitempty"`
}
+66
View File
@@ -0,0 +1,66 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// CardDAO extends the type BaseDAO.
type CardDAO struct {
Db dao.BaseDAO
}
const (
// CARDCOLLECTION defines the collection name for storing cards.
CARDCOLLECTION = "card"
// CARDMODEL defines the name of the card data model.
CARDMODEL = "kontor.tysc.card"
)
// FindAll retrieves the list of cards from the database.
func (m *CardDAO) FindAll() ([]Card, error) {
m.Db.Connect()
var cards []Card
err := m.Db.MongoDb.C(CARDCOLLECTION).Find(bson.M{"model": CARDMODEL}).All(&cards)
return cards, err
}
// FindByID returns an card with given id or returns the error.
func (m *CardDAO) FindByID(id string) (Card, error) {
m.Db.Connect()
var card Card
err := m.Db.MongoDb.C(CARDCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&card)
return card, err
}
// Insert a card into database.
func (m *CardDAO) Insert(card Card) error {
m.Db.Connect()
card.Model = CARDMODEL
err := m.Db.MongoDb.C(CARDCOLLECTION).Insert(&card)
return err
}
// Upsert a card into database.
func (m *CardDAO) Upsert(card Card) (*mgo.ChangeInfo, error) {
m.Db.Connect()
card.Model = CARDMODEL
info, err := m.Db.MongoDb.C(CARDCOLLECTION).Upsert(bson.M{"number": card.Number}, &card)
return info, err
}
// Update an existing card.
func (m *CardDAO) Update(card Card) error {
m.Db.Connect()
err := m.Db.MongoDb.C(CARDCOLLECTION).UpdateId(card.ID, &card)
return err
}
// Delete an existing card.
func (m *CardDAO) Delete(card Card) error {
m.Db.Connect()
err := m.Db.MongoDb.C(CARDCOLLECTION).Remove(&card)
return err
}
+110
View File
@@ -0,0 +1,110 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var cardModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Player", "string"},
{"Team", "string"},
{"Manufacturer", "string"},
{"CardSet", "string"},
{"ParallelSet", "string"},
{"InsertSet", "string"},
{"Rookie", "bool"},
{"Year", "int"},
{"Number", "int"},
{"Model", "string"},
}
func TestCardModel(t *testing.T) {
m := Card{}
if reflect.TypeOf(m).NumField() != len(cardModelTestTable) {
t.Fail()
}
for index, testData := range cardModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListCards(t *testing.T) {
var (
cardDao = CardDAO{Db: dao.TestDb}
)
cards, err := cardDao.FindAll()
if err != nil {
t.Fail()
}
if len(cards) != 0 {
t.Fail()
}
}
func TestInsertCard(t *testing.T) {
var (
cardDao = CardDAO{Db: dao.TestDb}
card = Card{}
cards []Card
)
card.ID = bson.NewObjectId()
card.Number = 1
err := cardDao.Insert(card)
if err != nil {
t.Fail()
}
cards, err = cardDao.FindAll()
if err != nil {
t.Fail()
}
if len(cards) != 1 {
t.Fail()
}
}
func TestUpsertCard(t *testing.T) {
var (
cardDao = CardDAO{Db: dao.TestDb}
card = Card{}
)
card.ID = bson.NewObjectId()
card.Number = 2
cardDao.Upsert(card)
cards, err := cardDao.FindAll()
if err != nil {
t.Fail()
}
if len(cards) != 2 {
t.Fail()
}
}
func TestDeleteCard(t *testing.T) {
var (
cardDao = CardDAO{Db: dao.TestDb}
)
cards, err := cardDao.FindAll()
if err != nil {
t.Fail()
}
for _, card := range cards {
cardDao.Delete(card)
}
cards, err = cardDao.FindAll()
if err != nil {
t.Fail()
}
if len(cards) != 0 {
t.Fail()
}
}
+13
View File
@@ -0,0 +1,13 @@
package tysc
import (
"gopkg.in/mgo.v2/bson"
)
// CardSet defines the data model for TYSC card sets with id, name and manufacturer.
type CardSet struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Manufacturer bson.ObjectId `json:"manufacturer" bson:"manufacturer,omitempty"`
Model string `json:"model" bson:"model,omitempty"`
}
+82
View File
@@ -0,0 +1,82 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// CardSetDAO extends the type BaseDAO.
type CardSetDAO struct {
Db dao.BaseDAO
}
const (
// CARDSETCOLLECTION defines the collection name for storing cards sets.
CARDSETCOLLECTION = "cardSet"
// CARDSETMODEL defines the name of the card set data model.
CARDSETMODEL = "kontor.tysc.cardSet"
)
// FindAll retrieves the list of card sets from the database.
func (m *CardSetDAO) FindAll() ([]CardSet, error) {
m.Db.Connect()
var cardSets []CardSet
err := m.Db.MongoDb.C(CARDSETCOLLECTION).Find(bson.M{"model": CARDSETMODEL}).All(&cardSets)
return cardSets, err
}
// FindByID returns a card set with given id or returns the error.
func (m *CardSetDAO) FindByID(id string) (CardSet, error) {
m.Db.Connect()
var cardSet CardSet
err := m.Db.MongoDb.C(CARDSETCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&cardSet)
return cardSet, err
}
// FindByManufacturer returns a card set with given manufacturer or returns the error.
func (m *CardSetDAO) FindByManufacturer(manufacturer string) ([]CardSet, error) {
m.Db.Connect()
var cardSets []CardSet
err := m.Db.MongoDb.C(CARDSETCOLLECTION).Find(bson.M{"model": CARDSETMODEL, "manufacturer": bson.ObjectIdHex(manufacturer)}).All(&cardSets)
return cardSets, err
}
// FindByName returns a card set with given name or returns the error.
func (m *CardSetDAO) FindByName(name string) (CardSet, error) {
m.Db.Connect()
var cardSet CardSet
err := m.Db.MongoDb.C(CARDSETCOLLECTION).Find(bson.M{"name": name, "model": CARDSETMODEL}).One(&cardSet)
return cardSet, err
}
// Insert an card set into database.
func (m *CardSetDAO) Insert(cardSet CardSet) error {
m.Db.Connect()
cardSet.Model = CARDSETMODEL
err := m.Db.MongoDb.C(CARDSETCOLLECTION).Insert(&cardSet)
return err
}
// Upsert an card set into database.
func (m *CardSetDAO) Upsert(cardSet CardSet) (*mgo.ChangeInfo, error) {
m.Db.Connect()
cardSet.Model = CARDSETMODEL
info, err := m.Db.MongoDb.C(CARDSETCOLLECTION).Upsert(bson.M{"name": cardSet.Name}, &cardSet)
return info, err
}
// Update an existing card set.
func (m *CardSetDAO) Update(cardSet CardSet) error {
m.Db.Connect()
err := m.Db.MongoDb.C(CARDSETCOLLECTION).UpdateId(cardSet.ID, &cardSet)
return err
}
// Delete an existing card set.
func (m *CardSetDAO) Delete(cardSet CardSet) error {
m.Db.Connect()
err := m.Db.MongoDb.C(CARDSETCOLLECTION).Remove(&cardSet)
return err
}
+103
View File
@@ -0,0 +1,103 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var cardsetModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Name", "string"},
{"Manufacturer", "string"},
{"Model", "string"},
}
func TestCardSetModel(t *testing.T) {
m := CardSet{}
if reflect.TypeOf(m).NumField() != len(cardsetModelTestTable) {
t.Fail()
}
for index, testData := range cardsetModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListCardSets(t *testing.T) {
var (
cardsetDao = CardSetDAO{Db: dao.TestDb}
)
cardSets, err := cardsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(cardSets) != 0 {
t.Fail()
}
}
func TestInsertCardSet(t *testing.T) {
var (
cardsetDao = CardSetDAO{Db: dao.TestDb}
cardSet = CardSet{}
cardSets []CardSet
)
cardSet.ID = bson.NewObjectId()
cardSet.Name = "test"
err := cardsetDao.Insert(cardSet)
if err != nil {
t.Fail()
}
cardSets, err = cardsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(cardSets) != 1 {
t.Fail()
}
}
func TestUpsertCardSet(t *testing.T) {
var (
cardsetDao = CardSetDAO{Db: dao.TestDb}
cardSet = CardSet{}
)
cardSet.ID = bson.NewObjectId()
cardSet.Name = "test2"
cardsetDao.Upsert(cardSet)
cardSets, err := cardsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(cardSets) != 2 {
t.Fail()
}
}
func TestDeleteCardSet(t *testing.T) {
var (
cardsetDao = CardSetDAO{Db: dao.TestDb}
)
cardSets, err := cardsetDao.FindAll()
if err != nil {
t.Fail()
}
for _, cardSet := range cardSets {
cardsetDao.Delete(cardSet)
}
cardSets, err = cardsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(cardSets) != 0 {
t.Fail()
}
}
+13
View File
@@ -0,0 +1,13 @@
package tysc
import (
"gopkg.in/mgo.v2/bson"
)
// InsertSet defines the data model for TYSC inserts sets with id, name and manufacturer.
type InsertSet struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Manufacturer bson.ObjectId `json:"manufacturer" bson:"manufacturer,omitempty"`
Model string `json:"model" bson:"model,omitempty"`
}
+82
View File
@@ -0,0 +1,82 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// InsertSetDAO extends the type BaseDAO.
type InsertSetDAO struct {
Db dao.BaseDAO
}
const (
// INSERTSETCOLLECTION defines the collection name for storing insert sets.
INSERTSETCOLLECTION = "insertSet"
// INSERTSETMODEL defines the name of the insert set data model.
INSERTSETMODEL = "kontor.tysc.insertSet"
)
// FindAll retrieves the list of cards from the database.
func (m *InsertSetDAO) FindAll() ([]InsertSet, error) {
m.Db.Connect()
var insertSets []InsertSet
err := m.Db.MongoDb.C(INSERTSETCOLLECTION).Find(bson.M{"model": INSERTSETMODEL}).All(&insertSets)
return insertSets, err
}
// FindByID returns an card with given id or returns the error.
func (m *InsertSetDAO) FindByID(id string) (InsertSet, error) {
m.Db.Connect()
var insertSet InsertSet
err := m.Db.MongoDb.C(INSERTSETCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&insertSet)
return insertSet, err
}
// FindByManufacturer returns a insert set with given manufacturer or returns the error.
func (m *InsertSetDAO) FindByManufacturer(manufacturer string) ([]InsertSet, error) {
m.Db.Connect()
var insertSets []InsertSet
err := m.Db.MongoDb.C(INSERTSETCOLLECTION).Find(bson.M{"model": INSERTSETMODEL, "manufacturer": bson.ObjectIdHex(manufacturer)}).All(&insertSets)
return insertSets, err
}
// FindByName returns a insert set with given name or returns the error.
func (m *InsertSetDAO) FindByName(name string) (InsertSet, error) {
m.Db.Connect()
var insertSet InsertSet
err := m.Db.MongoDb.C(INSERTSETCOLLECTION).Find(bson.M{"name": name, "model": INSERTSETMODEL}).One(&insertSet)
return insertSet, err
}
// Insert an insert set into database.
func (m *InsertSetDAO) Insert(insertSet InsertSet) error {
m.Db.Connect()
insertSet.Model = INSERTSETMODEL
err := m.Db.MongoDb.C(INSERTSETCOLLECTION).Insert(&insertSet)
return err
}
// Upsert an insert set into database.
func (m *InsertSetDAO) Upsert(insertSet InsertSet) (*mgo.ChangeInfo, error) {
m.Db.Connect()
insertSet.Model = INSERTSETMODEL
info, err := m.Db.MongoDb.C(INSERTSETCOLLECTION).Upsert(bson.M{"name": insertSet.Name}, &insertSet)
return info, err
}
// Update an existing insert set.
func (m *InsertSetDAO) Update(insertSet InsertSet) error {
m.Db.Connect()
err := m.Db.MongoDb.C(INSERTSETCOLLECTION).UpdateId(insertSet.ID, &insertSet)
return err
}
// Delete an existing insert set.
func (m *InsertSetDAO) Delete(insertSet InsertSet) error {
m.Db.Connect()
err := m.Db.MongoDb.C(INSERTSETCOLLECTION).Remove(&insertSet)
return err
}
+103
View File
@@ -0,0 +1,103 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var insertsetModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Name", "string"},
{"Manufacturer", "string"},
{"Model", "string"},
}
func TestInsertSetModel(t *testing.T) {
m := InsertSet{}
if reflect.TypeOf(m).NumField() != len(insertsetModelTestTable) {
t.Fail()
}
for index, testData := range insertsetModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListInsertSets(t *testing.T) {
var (
insertsetDao = InsertSetDAO{Db: dao.TestDb}
)
insertSets, err := insertsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(insertSets) != 0 {
t.Fail()
}
}
func TestInsertInsertSet(t *testing.T) {
var (
insertsetDao = InsertSetDAO{Db: dao.TestDb}
insertSet = InsertSet{}
insertSets []InsertSet
)
insertSet.ID = bson.NewObjectId()
insertSet.Name = "test"
err := insertsetDao.Insert(insertSet)
if err != nil {
t.Fail()
}
insertSets, err = insertsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(insertSets) != 1 {
t.Fail()
}
}
func TestUpsertInsertSet(t *testing.T) {
var (
insertsetDao = InsertSetDAO{Db: dao.TestDb}
insertSet = InsertSet{}
)
insertSet.ID = bson.NewObjectId()
insertSet.Name = "test2"
insertsetDao.Upsert(insertSet)
insertSets, err := insertsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(insertSets) != 2 {
t.Fail()
}
}
func TestDeleteInsertSet(t *testing.T) {
var (
insertsetDao = InsertSetDAO{Db: dao.TestDb}
)
insertSets, err := insertsetDao.FindAll()
if err != nil {
t.Fail()
}
for _, insertSet := range insertSets {
insertsetDao.Delete(insertSet)
}
insertSets, err = insertsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(insertSets) != 0 {
t.Fail()
}
}
+12
View File
@@ -0,0 +1,12 @@
package tysc
import (
"gopkg.in/mgo.v2/bson"
)
// Manufacturer defines the data model for TYSC manufacturers with id, and name.
type Manufacturer struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Model string `json:"model" bson:"model,omitempty"`
}
+74
View File
@@ -0,0 +1,74 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// ManufacturerDAO extends the type BaseDAO.
type ManufacturerDAO struct {
Db dao.BaseDAO
}
const (
// MANUFACTURERCOLLECTION defines the collection name for storing manufacturers.
MANUFACTURERCOLLECTION = "manufacturer"
// MANUFACTURERMODEL defines the name of the manufacturer data model.
MANUFACTURERMODEL = "kontor.tysc.manufacturer"
)
// FindAll retrieves the list of manufacturers from the database.
func (m *ManufacturerDAO) FindAll() ([]Manufacturer, error) {
m.Db.Connect()
var manufacturers []Manufacturer
err := m.Db.MongoDb.C(MANUFACTURERCOLLECTION).Find(bson.M{"model": MANUFACTURERMODEL}).All(&manufacturers)
return manufacturers, err
}
// FindByID returns a manufacturer with given id or returns the error.
func (m *ManufacturerDAO) FindByID(id string) (Manufacturer, error) {
m.Db.Connect()
var manufacturer Manufacturer
err := m.Db.MongoDb.C(MANUFACTURERCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&manufacturer)
return manufacturer, err
}
// FindByName returns a manufacturer with given name or returns the error.
func (m *ManufacturerDAO) FindByName(name string) (Manufacturer, error) {
m.Db.Connect()
var manufacturer Manufacturer
err := m.Db.MongoDb.C(MANUFACTURERCOLLECTION).Find(bson.M{"name": name, "model": MANUFACTURERMODEL}).One(&manufacturer)
return manufacturer, err
}
// Insert a manufacturer into database.
func (m *ManufacturerDAO) Insert(manufacturer Manufacturer) error {
m.Db.Connect()
manufacturer.Model = MANUFACTURERMODEL
err := m.Db.MongoDb.C(MANUFACTURERCOLLECTION).Insert(&manufacturer)
return err
}
// Upsert a manufacturer into database.
func (m *ManufacturerDAO) Upsert(manufacturer Manufacturer) (*mgo.ChangeInfo, error) {
m.Db.Connect()
manufacturer.Model = MANUFACTURERMODEL
info, err := m.Db.MongoDb.C(MANUFACTURERCOLLECTION).Upsert(bson.M{"name": manufacturer.Name}, &manufacturer)
return info, err
}
// Update an existing manufacturer.
func (m *ManufacturerDAO) Update(manufacturer Manufacturer) error {
m.Db.Connect()
err := m.Db.MongoDb.C(MANUFACTURERCOLLECTION).UpdateId(manufacturer.ID, &manufacturer)
return err
}
// Delete an existing manufacturer.
func (m *ManufacturerDAO) Delete(manufacturer Manufacturer) error {
m.Db.Connect()
err := m.Db.MongoDb.C(MANUFACTURERCOLLECTION).Remove(&manufacturer)
return err
}
+102
View File
@@ -0,0 +1,102 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var manufacturerModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Name", "string"},
{"Model", "string"},
}
func TestManufacturerModel(t *testing.T) {
m := Manufacturer{}
if reflect.TypeOf(m).NumField() != len(manufacturerModelTestTable) {
t.Fail()
}
for index, testData := range manufacturerModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListManufacturers(t *testing.T) {
var (
manufacturerDao = ManufacturerDAO{Db: dao.TestDb}
)
manufacturers, err := manufacturerDao.FindAll()
if err != nil {
t.Fail()
}
if len(manufacturers) != 0 {
t.Fail()
}
}
func TestInsertManufacturer(t *testing.T) {
var (
manufacturerDao = ManufacturerDAO{Db: dao.TestDb}
manufacturer = Manufacturer{}
manufacturers []Manufacturer
)
manufacturer.ID = bson.NewObjectId()
manufacturer.Name = "test"
err := manufacturerDao.Insert(manufacturer)
if err != nil {
t.Fail()
}
manufacturers, err = manufacturerDao.FindAll()
if err != nil {
t.Fail()
}
if len(manufacturers) != 1 {
t.Fail()
}
}
func TestUpsertManufacturer(t *testing.T) {
var (
manufacturerDao = ManufacturerDAO{Db: dao.TestDb}
manufacturer = Manufacturer{}
)
manufacturer.ID = bson.NewObjectId()
manufacturer.Name = "test2"
manufacturerDao.Upsert(manufacturer)
manufacturers, err := manufacturerDao.FindAll()
if err != nil {
t.Fail()
}
if len(manufacturers) != 2 {
t.Fail()
}
}
func TestDeleteManufacturer(t *testing.T) {
var (
manufacturerDao = ManufacturerDAO{Db: dao.TestDb}
)
manufacturers, err := manufacturerDao.FindAll()
if err != nil {
t.Fail()
}
for _, manufacturer := range manufacturers {
manufacturerDao.Delete(manufacturer)
}
manufacturers, err = manufacturerDao.FindAll()
if err != nil {
t.Fail()
}
if len(manufacturers) != 0 {
t.Fail()
}
}
+13
View File
@@ -0,0 +1,13 @@
package tysc
import (
"gopkg.in/mgo.v2/bson"
)
// ParallelSet defines the data model for TYSC parallel sets with id, name and manufacturer.
type ParallelSet struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Manufacturer bson.ObjectId `json:"manufacturer" bson:"manufacturer,omitempty"`
Model string `json:"model" bson:"model,omitempty"`
}
+82
View File
@@ -0,0 +1,82 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// ParallelSetDAO extends the type BaseDAO.
type ParallelSetDAO struct {
Db dao.BaseDAO
}
const (
// PARALLELSETCOLLECTION defines the collection name for storing parallel sets.
PARALLELSETCOLLECTION = "parallelSet"
// PARALLELSETMODEL defines the name of the parallel set data model.
PARALLELSETMODEL = "kontor.tysc.parallelSet"
)
// FindAll retrieves the list of parallel sets from the database.
func (m *ParallelSetDAO) FindAll() ([]ParallelSet, error) {
m.Db.Connect()
var parallelSets []ParallelSet
err := m.Db.MongoDb.C(PARALLELSETCOLLECTION).Find(bson.M{"model": PARALLELSETMODEL}).All(&parallelSets)
return parallelSets, err
}
// FindByID returns a parallel set with given id or returns the error.
func (m *ParallelSetDAO) FindByID(id string) (ParallelSet, error) {
m.Db.Connect()
var parallelSet ParallelSet
err := m.Db.MongoDb.C(PARALLELSETCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&parallelSet)
return parallelSet, err
}
// FindByManufacturer returns a paralle set with given manufacturer or returns the error.
func (m *ParallelSetDAO) FindByManufacturer(manufacturer string) ([]ParallelSet, error) {
m.Db.Connect()
var parallelSets []ParallelSet
err := m.Db.MongoDb.C(PARALLELSETCOLLECTION).Find(bson.M{"model": PARALLELSETMODEL, "manufacturer": bson.ObjectIdHex(manufacturer)}).All(&parallelSets)
return parallelSets, err
}
// FindByName returns a parallel set with given name or returns the error.
func (m *ParallelSetDAO) FindByName(name string) (ParallelSet, error) {
m.Db.Connect()
var parallelSet ParallelSet
err := m.Db.MongoDb.C(PARALLELSETCOLLECTION).Find(bson.M{"name": name, "model": PARALLELSETMODEL}).One(&parallelSet)
return parallelSet, err
}
// Insert a parallel set into database.
func (m *ParallelSetDAO) Insert(parallelSet ParallelSet) error {
m.Db.Connect()
parallelSet.Model = PARALLELSETMODEL
err := m.Db.MongoDb.C(PARALLELSETCOLLECTION).Insert(&parallelSet)
return err
}
// Upsert a parallel set into database.
func (m *ParallelSetDAO) Upsert(parallelSet ParallelSet) (*mgo.ChangeInfo, error) {
m.Db.Connect()
parallelSet.Model = PARALLELSETMODEL
info, err := m.Db.MongoDb.C(PARALLELSETCOLLECTION).Upsert(bson.M{"name": parallelSet.Name}, &parallelSet)
return info, err
}
// Update an existing parallel set.
func (m *ParallelSetDAO) Update(parallelSet ParallelSet) error {
m.Db.Connect()
err := m.Db.MongoDb.C(PARALLELSETCOLLECTION).UpdateId(parallelSet.ID, &parallelSet)
return err
}
// Delete an existing parallel set.
func (m *ParallelSetDAO) Delete(parallelSet ParallelSet) error {
m.Db.Connect()
err := m.Db.MongoDb.C(PARALLELSETCOLLECTION).Remove(&parallelSet)
return err
}
+103
View File
@@ -0,0 +1,103 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var parallelsetModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Name", "string"},
{"Manufacturer", "string"},
{"Model", "string"},
}
func TestParallelSetModel(t *testing.T) {
m := ParallelSet{}
if reflect.TypeOf(m).NumField() != len(parallelsetModelTestTable) {
t.Fail()
}
for index, testData := range parallelsetModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListParallelSets(t *testing.T) {
var (
parallelsetDao = ParallelSetDAO{Db: dao.TestDb}
)
parallelSets, err := parallelsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(parallelSets) != 0 {
t.Fail()
}
}
func TestInsertParallelSet(t *testing.T) {
var (
parallelsetDao = ParallelSetDAO{Db: dao.TestDb}
parallelSet = ParallelSet{}
parallelSets []ParallelSet
)
parallelSet.ID = bson.NewObjectId()
parallelSet.Name = "test"
err := parallelsetDao.Insert(parallelSet)
if err != nil {
t.Fail()
}
parallelSets, err = parallelsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(parallelSets) != 1 {
t.Fail()
}
}
func TestUpsertParallelSet(t *testing.T) {
var (
parallelsetDao = ParallelSetDAO{Db: dao.TestDb}
parallelSet = ParallelSet{}
)
parallelSet.ID = bson.NewObjectId()
parallelSet.Name = "test2"
parallelsetDao.Upsert(parallelSet)
parallelSets, err := parallelsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(parallelSets) != 2 {
t.Fail()
}
}
func TestDeleteParallelSet(t *testing.T) {
var (
parallelsetDao = ParallelSetDAO{Db: dao.TestDb}
)
parallelSets, err := parallelsetDao.FindAll()
if err != nil {
t.Fail()
}
for _, parallelSet := range parallelSets {
parallelsetDao.Delete(parallelSet)
}
parallelSets, err = parallelsetDao.FindAll()
if err != nil {
t.Fail()
}
if len(parallelSets) != 0 {
t.Fail()
}
}
+13
View File
@@ -0,0 +1,13 @@
package tysc
import (
"gopkg.in/mgo.v2/bson"
)
// Player defines the data model for TYSC players with id, first and lastname.
type Player struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Firstname string `json:"firstname" bson:"firstname"`
Lastname string `json:"lastname" bson:"lastname"`
Model string `json:"model" bson:"model,omitempty"`
}
+74
View File
@@ -0,0 +1,74 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// PlayerDAO extends the type BaseDAO.
type PlayerDAO struct {
Db dao.BaseDAO
}
const (
// PLAYERCOLLECTION defines the collection name for storing players.
PLAYERCOLLECTION = "player"
// PLAYERMODEL defines the name of the player data model.
PLAYERMODEL = "kontor.tysc.player"
)
// FindAll retrieves the list of players from the database.
func (m *PlayerDAO) FindAll() ([]Player, error) {
m.Db.Connect()
var players []Player
err := m.Db.MongoDb.C(PLAYERCOLLECTION).Find(bson.M{"model": PLAYERMODEL}).All(&players)
return players, err
}
// FindByID returns a player with given id or returns the error.
func (m *PlayerDAO) FindByID(id string) (Player, error) {
m.Db.Connect()
var player Player
err := m.Db.MongoDb.C(PLAYERCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&player)
return player, err
}
// FindByLastName returns a player with given last name or returns the error.
func (m *PlayerDAO) FindByLastName(lastname string) (Player, error) {
m.Db.Connect()
var player Player
err := m.Db.MongoDb.C(PLAYERCOLLECTION).Find(bson.M{"lastname": lastname, "model": PLAYERMODEL}).One(&player)
return player, err
}
// Insert a player into database.
func (m *PlayerDAO) Insert(player Player) error {
m.Db.Connect()
player.Model = PLAYERMODEL
err := m.Db.MongoDb.C(PLAYERCOLLECTION).Insert(&player)
return err
}
// Upsert a player into database.
func (m *PlayerDAO) Upsert(player Player) (*mgo.ChangeInfo, error) {
m.Db.Connect()
player.Model = PLAYERMODEL
info, err := m.Db.MongoDb.C(PLAYERCOLLECTION).Upsert(bson.M{"lastname": player.Lastname}, &player)
return info, err
}
// Update an existing player.
func (m *PlayerDAO) Update(player Player) error {
m.Db.Connect()
err := m.Db.MongoDb.C(PLAYERCOLLECTION).UpdateId(player.ID, &player)
return err
}
// Delete an existing player.
func (m *PlayerDAO) Delete(player Player) error {
m.Db.Connect()
err := m.Db.MongoDb.C(PLAYERCOLLECTION).Remove(&player)
return err
}
+103
View File
@@ -0,0 +1,103 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var playerModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Firstname", "string"},
{"Lastname", "string"},
{"Model", "string"},
}
func TestPlayerModel(t *testing.T) {
m := Player{}
if reflect.TypeOf(m).NumField() != len(playerModelTestTable) {
t.Fail()
}
for index, testData := range playerModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListPlayers(t *testing.T) {
var (
playerDao = PlayerDAO{Db: dao.TestDb}
)
players, err := playerDao.FindAll()
if err != nil {
t.Fail()
}
if players != nil {
t.Fail()
}
}
func TestInsertPlayer(t *testing.T) {
var (
playerDao = PlayerDAO{Db: dao.TestDb}
player = Player{}
players []Player
)
player.ID = bson.NewObjectId()
player.Lastname = "test"
err := playerDao.Insert(player)
if err != nil {
t.Fail()
}
players, err = playerDao.FindAll()
if err != nil {
t.Fail()
}
if len(players) != 1 {
t.Fail()
}
}
func TestUpsertPlayer(t *testing.T) {
var (
playerDao = PlayerDAO{Db: dao.TestDb}
player = Player{}
)
player.ID = bson.NewObjectId()
player.Lastname = "test2"
playerDao.Upsert(player)
players, err := playerDao.FindAll()
if err != nil {
t.Fail()
}
if len(players) != 2 {
t.Fail()
}
}
func TestDeletePlayer(t *testing.T) {
var (
playerDao = PlayerDAO{Db: dao.TestDb}
)
players, err := playerDao.FindAll()
if err != nil {
t.Fail()
}
for _, player := range players {
playerDao.Delete(player)
}
players, err = playerDao.FindAll()
if err != nil {
t.Fail()
}
if len(players) != 0 {
t.Fail()
}
}
+14
View File
@@ -0,0 +1,14 @@
package tysc
import (
"gopkg.in/mgo.v2/bson"
)
// Position defines the data model for TYSC positions with id, name, description and sport.
type Position struct {
ID bson.ObjectId `json:"_id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Description string `json:"description" bson:"description"`
Sport bson.ObjectId `json:"sport" bson:"sport,omitempty"`
Model string `json:"model" bson:"model,omitempty"`
}
+74
View File
@@ -0,0 +1,74 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
// PositionDAO extends the type BaseDAO.
type PositionDAO struct {
Db dao.BaseDAO
}
const (
// POSITIONCOLLECTION defines the collection name for storing positions.
POSITIONCOLLECTION = "position"
// POSITIONMODEL defines the name of the position data model.
POSITIONMODEL = "kontor.tysc.position"
)
// FindAll retrieves the list of positions from the database.
func (m *PositionDAO) FindAll() ([]Position, error) {
m.Db.Connect()
var positions []Position
err := m.Db.MongoDb.C(POSITIONCOLLECTION).Find(bson.M{"model": POSITIONMODEL}).All(&positions)
return positions, err
}
// FindByID returns a position with given id or returns the error.
func (m *PositionDAO) FindByID(id string) (Position, error) {
m.Db.Connect()
var position Position
err := m.Db.MongoDb.C(POSITIONCOLLECTION).FindId(bson.ObjectIdHex(id)).One(&position)
return position, err
}
// FindByName returns a position with given name or returns the error.
func (m *PositionDAO) FindByName(name string) (Position, error) {
m.Db.Connect()
var position Position
err := m.Db.MongoDb.C(POSITIONCOLLECTION).Find(bson.M{"name": name, "model": POSITIONMODEL}).One(&position)
return position, err
}
// Insert a position into database.
func (m *PositionDAO) Insert(position Position) error {
m.Db.Connect()
position.Model = POSITIONMODEL
err := m.Db.MongoDb.C(POSITIONCOLLECTION).Insert(&position)
return err
}
// Upsert a position into database.
func (m *PositionDAO) Upsert(position Position) (*mgo.ChangeInfo, error) {
m.Db.Connect()
position.Model = POSITIONMODEL
info, err := m.Db.MongoDb.C(POSITIONCOLLECTION).Upsert(bson.M{"name": position.Name}, &position)
return info, err
}
// Update an existing position.
func (m *PositionDAO) Update(position Position) error {
m.Db.Connect()
err := m.Db.MongoDb.C(POSITIONCOLLECTION).UpdateId(position.ID, &position)
return err
}
// Delete an existing position.
func (m *PositionDAO) Delete(position Position) error {
m.Db.Connect()
err := m.Db.MongoDb.C(POSITIONCOLLECTION).Remove(&position)
return err
}
+104
View File
@@ -0,0 +1,104 @@
package tysc
import (
"gitlab.thpeetz.de/kontor/kontor-go/pkg/dao"
"reflect"
"testing"
"gopkg.in/mgo.v2/bson"
)
var positionModelTestTable = []struct {
name string
typeName string
}{
{"Id", "string"},
{"Name", "string"},
{"Description", "string"},
{"Sport", "string"},
{"Model", "string"},
}
func TestPositionModel(t *testing.T) {
m := Position{}
if reflect.TypeOf(m).NumField() != len(positionModelTestTable) {
t.Fail()
}
for index, testData := range positionModelTestTable {
givenType := reflect.TypeOf(m).Field(index).Type.Kind().String()
if givenType != testData.typeName {
t.Fail()
}
}
}
func TestListPositions(t *testing.T) {
var (
positionDao = PositionDAO{Db: dao.TestDb}
)
positions, err := positionDao.FindAll()
if err != nil {
t.Fail()
}
if len(positions) != 0 {
t.Fail()
}
}
func TestInsertPosition(t *testing.T) {
var (
positionDao = PositionDAO{Db: dao.TestDb}
position = Position{}
positions []Position
)
position.ID = bson.NewObjectId()
position.Name = "test"
err := positionDao.Insert(position)
if err != nil {
t.Fail()
}
positions, err = positionDao.FindAll()
if err != nil {
t.Fail()
}
if len(positions) != 1 {
t.Fail()
}
}
func TestUpsertPosition(t *testing.T) {
var (
positionDao = PositionDAO{Db: dao.TestDb}
position = Position{}
)
position.ID = bson.NewObjectId()
position.Name = "test2"
positionDao.Upsert(position)
positions, err := positionDao.FindAll()
if err != nil {
t.Fail()
}
if len(positions) != 2 {
t.Fail()
}
}
func TestDeletePosition(t *testing.T) {
var (
positionDao = PositionDAO{Db: dao.TestDb}
)
positions, err := positionDao.FindAll()
if err != nil {
t.Fail()
}
for _, position := range positions {
positionDao.Delete(position)
}
positions, err = positionDao.FindAll()
if err != nil {
t.Fail()
}
if len(positions) != 0 {
t.Fail()
}
}

Some files were not shown because too many files have changed in this diff Show More