| @ -1,13 +1,8 @@ | |||
| composer.phar | |||
| /vendor/ | |||
| node_modules | |||
| .env | |||
| *.log | |||
| rysnc_exclude | |||
| /storage/database | |||
| /storage/files | |||
| storage/database/* | |||
| !storage/database/.gitkeep | |||
| storage/cache/* | |||
| !storage/cache/.gitkeep | |||
| !/storage/database/.gitkeep | |||
| !/storage/files/.gitkeep | |||
| @ -1,28 +0,0 @@ | |||
| <?php | |||
| namespace App\Flight; | |||
| use Flight; | |||
| /** | |||
| * abstract FlightAbstract get instance of flight engine | |||
| * | |||
| * | |||
| * @author Björn Hase | |||
| * @license http://opensource.org/licenses/MIT The MIT License | |||
| * | |||
| */ | |||
| abstract class FlightAbstract | |||
| { | |||
| /** object of flight */ | |||
| protected $app; | |||
| /** | |||
| * getting object of flight | |||
| * | |||
| */ | |||
| public function __construct() | |||
| { | |||
| $this->app = Flight::app(); | |||
| } | |||
| } | |||
| @ -1,42 +0,0 @@ | |||
| <?php | |||
| /** | |||
| * fake function for blade @inject | |||
| * | |||
| * @param string $class | |||
| * @return object | |||
| */ | |||
| function app($class) | |||
| { | |||
| return new $class(); | |||
| } | |||
| /** | |||
| * function similar to blade asset | |||
| * | |||
| * @param $path | |||
| * @return string | |||
| * | |||
| */ | |||
| function asset($path, $prefix = '/public') | |||
| { | |||
| // get flight | |||
| $app = Flight::app(); | |||
| // getting basePath | |||
| $basePath = $app->get('basePath'); | |||
| // path to mix-manifest | |||
| $file = $app->get('basePath').'mix-manifest.json'; | |||
| if (file_exists($file)) { | |||
| $manifest = file_get_contents($file); | |||
| $files = json_decode($manifest, true); | |||
| if (isset($files[$prefix.$path])) { | |||
| $path = str_replace($prefix, '', $files[$prefix.$path]); | |||
| } | |||
| } | |||
| return $path; | |||
| } | |||
| @ -1,39 +0,0 @@ | |||
| <?php | |||
| namespace App\Http; | |||
| use Rakit\Validation\Validator; | |||
| use App\Flight\FlightAbstract; | |||
| use App\Models\Bucket; | |||
| use Carbon\Carbon; | |||
| /** | |||
| * | |||
| * | |||
| * | |||
| * | |||
| * @author Björn Hase | |||
| * @link https://gitea.tentakelfabrik.de/mITSM/feedback GitHub Repository | |||
| * | |||
| * | |||
| */ | |||
| class Bucket extends FlightAbstract | |||
| { | |||
| public function viewAction($id) | |||
| { | |||
| $this->app->render('bucket', [ | |||
| 'id' => $id | |||
| ]); | |||
| } | |||
| public function indexAction($id, $visibilty, $page) | |||
| { | |||
| $bucketStore = new Bucket(); | |||
| $publicBuckets = $bucketStore->findBy(); | |||
| $this->app->json([ | |||
| 'publicBuckets' => $publicBuckets | |||
| ]); | |||
| } | |||
| } | |||
| @ -1,29 +0,0 @@ | |||
| <?php | |||
| namespace App\Http; | |||
| use Rakit\Validation\Validator; | |||
| use App\Flight\FlightAbstract; | |||
| use App\Models\Bucket; | |||
| use Carbon\Carbon; | |||
| /** | |||
| * | |||
| * | |||
| * | |||
| * | |||
| * @author Björn Hase | |||
| * @link https://gitea.tentakelfabrik.de/mITSM/feedback GitHub Repository | |||
| * | |||
| * | |||
| */ | |||
| class Home extends FlightAbstract | |||
| { | |||
| public function indexAction() | |||
| { | |||
| $this->app->render('home', [ | |||
| ]); | |||
| } | |||
| } | |||
| @ -1,58 +0,0 @@ | |||
| <?php | |||
| namespace App\Http; | |||
| use Rakit\Validation\Validator; | |||
| use App\Flight\FlightAbstract; | |||
| use App\Models\Bucket; | |||
| use Carbon\Carbon; | |||
| /** | |||
| * | |||
| * | |||
| * | |||
| * | |||
| * @author Björn Hase | |||
| * @link https://gitea.tentakelfabrik.de/mITSM/feedback GitHub Repository | |||
| * | |||
| * | |||
| */ | |||
| class Note extends FlightAbstract | |||
| { | |||
| /** | |||
| * | |||
| * @param integer $id | |||
| * | |||
| */ | |||
| public function viewAction($id) | |||
| { | |||
| $this->app->render('bucket', [ | |||
| 'id' => $id | |||
| ]); | |||
| } | |||
| public function indexAction($bucketId) | |||
| { | |||
| $noteStore = new Note(); | |||
| $notes = $noteStore->findBy(); | |||
| $this->app->json([ | |||
| 'data' => $notes, | |||
| 'page' => $page | |||
| ]); | |||
| } | |||
| public function createAction($bucketId) | |||
| { | |||
| $result = [ | |||
| 'success' => false | |||
| ]; | |||
| $noteStore = new Note(); | |||
| $this->app->json([ | |||
| 'data' => $notes, | |||
| ]); | |||
| } | |||
| } | |||
| @ -1,26 +0,0 @@ | |||
| <?php | |||
| namespace App\Models; | |||
| /** | |||
| * Store for Courses | |||
| * | |||
| * | |||
| * @author Björn Hase | |||
| * @link https://gitea.tentakelfabrik.de/mITSM/feedback GitHub Repository | |||
| * | |||
| */ | |||
| class Bucket extends ModelAbstract | |||
| { | |||
| // name of store | |||
| protected $name = 'buckets'; | |||
| public function findByVisiblity($visiblity) | |||
| { | |||
| return $this->store->findBy( | |||
| [ 'visiblity' => $visiblity ], | |||
| [ 'created_at' => 'ASC' ], | |||
| 100 | |||
| ); | |||
| } | |||
| } | |||
| @ -1,46 +0,0 @@ | |||
| <?php | |||
| namespace App\Models; | |||
| use SleekDB\Store; | |||
| use SleekDB\Query; | |||
| /** | |||
| * Abstract Class for Stores | |||
| * | |||
| * | |||
| * @author Björn Hase | |||
| * @link https://gitea.tentakelfabrik.de/mITSM/feedback GitHub Repository | |||
| * | |||
| */ | |||
| class ModelAbstract | |||
| { | |||
| // store of model | |||
| public $store; | |||
| // name of store | |||
| protected $name; | |||
| // configuration of store | |||
| protected $configuration = [ | |||
| 'auto_cache' => true, | |||
| 'cache_lifetime' => null, | |||
| 'timeout' => 120, | |||
| 'primary_key' => '_id', | |||
| 'search' => [ | |||
| 'min_length' => 2, | |||
| 'mode' => 'or', | |||
| 'score_key' => 'scoreKey', | |||
| 'algorithm' => Query::SEARCH_ALGORITHM['hits'] | |||
| ] | |||
| ]; | |||
| /** | |||
| * | |||
| * | |||
| */ | |||
| public function __construct() | |||
| { | |||
| $this->store = new Store($this->name, __DIR__.'/../../storage/database', $this->configuration); | |||
| } | |||
| } | |||
| @ -1,17 +0,0 @@ | |||
| <?php | |||
| namespace App\Models; | |||
| /** | |||
| * Store for Tags | |||
| * | |||
| * | |||
| * @author Björn Hase | |||
| * @link https://gitea.tentakelfabrik.de/mITSM/feedback GitHub Repository | |||
| * | |||
| */ | |||
| class Tag extends ModelAbstract | |||
| { | |||
| // name of store | |||
| protected $name = 'tags'; | |||
| } | |||
| @ -1,17 +0,0 @@ | |||
| <?php | |||
| namespace App\Models; | |||
| /** | |||
| * Store for Users | |||
| * | |||
| * | |||
| * @author Björn Hase | |||
| * @link https://gitea.tentakelfabrik.de/mITSM/feedback GitHub Repository | |||
| * | |||
| */ | |||
| class User extends ModelAbstract | |||
| { | |||
| // name of store | |||
| protected $name = 'users'; | |||
| } | |||
| @ -1,31 +0,0 @@ | |||
| <?php | |||
| // adding functions | |||
| require_once(__DIR__.'/Flight/Functions.php'); | |||
| // adding env | |||
| $env = Dotenv\Dotenv::createImmutable(__DIR__.'/..'); | |||
| $env->load(); | |||
| // display all errors if debug is true | |||
| if (getenv('DEBUG') === true) { | |||
| error_reporting(E_ALL); | |||
| ini_set('display_errors', 1); | |||
| } | |||
| // create app | |||
| $app = Flight::app(); | |||
| // setting view path | |||
| $app->set('flight.views.path', __DIR__.'/../resources/views'); | |||
| // adding blade for templates | |||
| Flight::register('view', 'Jenssegers\Blade\Blade', [ $app->get('flight.views.path'), __DIR__.'/../storage/cache']); | |||
| Flight::map('render', function($view, $data) { | |||
| echo Flight::view()->make($view, $data); | |||
| }); | |||
| // setting path | |||
| $app->set('basePath', __DIR__.'/../'); | |||
| $app->set('publicPath', __DIR__.'/../public'); | |||
| $app->set('storagePath', __DIR__.'/../storage'); | |||
| @ -1,16 +0,0 @@ | |||
| { | |||
| "require": { | |||
| "mikecao/flight": "^1.3", | |||
| "rakibtg/sleekdb": "^2.11", | |||
| "vlucas/phpdotenv": "^5.3", | |||
| "jenssegers/blade": "^1.4", | |||
| "rakit/validation": "^1.4", | |||
| "nesbot/carbon": "^2.49", | |||
| "microweber/screen": "^1.0" | |||
| }, | |||
| "autoload": { | |||
| "psr-4": { | |||
| "App\\": "app/" | |||
| } | |||
| } | |||
| } | |||
| @ -0,0 +1,5 @@ | |||
| { | |||
| "/public/js/index.js": "/public/js/index.js", | |||
| "/public/js/critical.js": "/public/js/critical.js", | |||
| "/public/css/index.css": "/public/css/index.css" | |||
| } | |||
| @ -0,0 +1,19 @@ | |||
| { | |||
| "private": true, | |||
| "scripts": { | |||
| "test": "echo \"Error: no test specified\" && exit 1" | |||
| }, | |||
| "author": "me@herr-hase.wtf", | |||
| "license": "GPL", | |||
| "dependencies": { | |||
| "turbolinks": "^5.2.0" | |||
| }, | |||
| "devDependencies": { | |||
| "@riotjs/webpack-loader": "^5.0.0", | |||
| "cross-env": "^7.0.3", | |||
| "laravel-mix": "^6.0.25", | |||
| "resolve-url-loader": "^4.0.0", | |||
| "sass": "^1.35.1", | |||
| "sass-loader": "^12.1.0" | |||
| } | |||
| } | |||
| @ -0,0 +1,5 @@ | |||
| .turbolinks-progress-bar { | |||
| width: 5px; | |||
| height: 100%; | |||
| background-color: blue; | |||
| } | |||
| @ -1,18 +0,0 @@ | |||
| <?php | |||
| require __DIR__.'/../vendor/autoload.php'; | |||
| require __DIR__.'/../app/bootstrap.php'; | |||
| $app->route('GET /', array(new App\Http\Home, 'homeAction')); | |||
| $app->route('GET /bucket/@id:[0-9]', array(new App\Http\Bucket, 'viewAction')); | |||
| $app->route('GET /bucket/@id:[0-9]', array(new App\Http\Bucket, 'indexAction')); | |||
| $app->route('POST /bucket', array(new App\Http\Bucket, 'createAction')); | |||
| $app->route('PUT /bucket/@id:[0-9]', array(new App\Http\Bucket, 'updateAction')); | |||
| $app->route('DELETE /bucket/@id:[0-9]', array(new App\Http\Bucket, 'destroyAction')); | |||
| $app->route('POST /note', array(new App\Http\Note, 'createAction')); | |||
| $app->route('PUT /note/@id:[0-9]', array(new App\Http\Note, 'updateAction')); | |||
| $app->route('DELETE /note/@id:[0-9]', array(new App\Http\Note, 'destroyAction')); | |||
| $app->start(); | |||
| @ -0,0 +1,166 @@ | |||
| /******/ (() => { // webpackBootstrap | |||
| /******/ var __webpack_modules__ = ({ | |||
| /***/ "./resources/js/index.js": | |||
| /*!*******************************!*\ | |||
| !*** ./resources/js/index.js ***! | |||
| \*******************************/ | |||
| /***/ (() => { | |||
| /***/ }), | |||
| /***/ "./resources/scss/index.scss": | |||
| /*!***********************************!*\ | |||
| !*** ./resources/scss/index.scss ***! | |||
| \***********************************/ | |||
| /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { | |||
| "use strict"; | |||
| __webpack_require__.r(__webpack_exports__); | |||
| // extracted by mini-css-extract-plugin | |||
| /***/ }) | |||
| /******/ }); | |||
| /************************************************************************/ | |||
| /******/ // The module cache | |||
| /******/ var __webpack_module_cache__ = {}; | |||
| /******/ | |||
| /******/ // The require function | |||
| /******/ function __webpack_require__(moduleId) { | |||
| /******/ // Check if module is in cache | |||
| /******/ var cachedModule = __webpack_module_cache__[moduleId]; | |||
| /******/ if (cachedModule !== undefined) { | |||
| /******/ return cachedModule.exports; | |||
| /******/ } | |||
| /******/ // Create a new module (and put it into the cache) | |||
| /******/ var module = __webpack_module_cache__[moduleId] = { | |||
| /******/ // no module.id needed | |||
| /******/ // no module.loaded needed | |||
| /******/ exports: {} | |||
| /******/ }; | |||
| /******/ | |||
| /******/ // Execute the module function | |||
| /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); | |||
| /******/ | |||
| /******/ // Return the exports of the module | |||
| /******/ return module.exports; | |||
| /******/ } | |||
| /******/ | |||
| /******/ // expose the modules object (__webpack_modules__) | |||
| /******/ __webpack_require__.m = __webpack_modules__; | |||
| /******/ | |||
| /************************************************************************/ | |||
| /******/ /* webpack/runtime/chunk loaded */ | |||
| /******/ (() => { | |||
| /******/ var deferred = []; | |||
| /******/ __webpack_require__.O = (result, chunkIds, fn, priority) => { | |||
| /******/ if(chunkIds) { | |||
| /******/ priority = priority || 0; | |||
| /******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1]; | |||
| /******/ deferred[i] = [chunkIds, fn, priority]; | |||
| /******/ return; | |||
| /******/ } | |||
| /******/ var notFulfilled = Infinity; | |||
| /******/ for (var i = 0; i < deferred.length; i++) { | |||
| /******/ var [chunkIds, fn, priority] = deferred[i]; | |||
| /******/ var fulfilled = true; | |||
| /******/ for (var j = 0; j < chunkIds.length; j++) { | |||
| /******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) { | |||
| /******/ chunkIds.splice(j--, 1); | |||
| /******/ } else { | |||
| /******/ fulfilled = false; | |||
| /******/ if(priority < notFulfilled) notFulfilled = priority; | |||
| /******/ } | |||
| /******/ } | |||
| /******/ if(fulfilled) { | |||
| /******/ deferred.splice(i--, 1) | |||
| /******/ result = fn(); | |||
| /******/ } | |||
| /******/ } | |||
| /******/ return result; | |||
| /******/ }; | |||
| /******/ })(); | |||
| /******/ | |||
| /******/ /* webpack/runtime/hasOwnProperty shorthand */ | |||
| /******/ (() => { | |||
| /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) | |||
| /******/ })(); | |||
| /******/ | |||
| /******/ /* webpack/runtime/make namespace object */ | |||
| /******/ (() => { | |||
| /******/ // define __esModule on exports | |||
| /******/ __webpack_require__.r = (exports) => { | |||
| /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { | |||
| /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | |||
| /******/ } | |||
| /******/ Object.defineProperty(exports, '__esModule', { value: true }); | |||
| /******/ }; | |||
| /******/ })(); | |||
| /******/ | |||
| /******/ /* webpack/runtime/jsonp chunk loading */ | |||
| /******/ (() => { | |||
| /******/ // no baseURI | |||
| /******/ | |||
| /******/ // object to store loaded and loading chunks | |||
| /******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched | |||
| /******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded | |||
| /******/ var installedChunks = { | |||
| /******/ "/public/js/index": 0, | |||
| /******/ "public/css/index": 0 | |||
| /******/ }; | |||
| /******/ | |||
| /******/ // no chunk on demand loading | |||
| /******/ | |||
| /******/ // no prefetching | |||
| /******/ | |||
| /******/ // no preloaded | |||
| /******/ | |||
| /******/ // no HMR | |||
| /******/ | |||
| /******/ // no HMR manifest | |||
| /******/ | |||
| /******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0); | |||
| /******/ | |||
| /******/ // install a JSONP callback for chunk loading | |||
| /******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => { | |||
| /******/ var [chunkIds, moreModules, runtime] = data; | |||
| /******/ // add "moreModules" to the modules object, | |||
| /******/ // then flag all "chunkIds" as loaded and fire callback | |||
| /******/ var moduleId, chunkId, i = 0; | |||
| /******/ for(moduleId in moreModules) { | |||
| /******/ if(__webpack_require__.o(moreModules, moduleId)) { | |||
| /******/ __webpack_require__.m[moduleId] = moreModules[moduleId]; | |||
| /******/ } | |||
| /******/ } | |||
| /******/ if(runtime) var result = runtime(__webpack_require__); | |||
| /******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data); | |||
| /******/ for(;i < chunkIds.length; i++) { | |||
| /******/ chunkId = chunkIds[i]; | |||
| /******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) { | |||
| /******/ installedChunks[chunkId][0](); | |||
| /******/ } | |||
| /******/ installedChunks[chunkIds[i]] = 0; | |||
| /******/ } | |||
| /******/ return __webpack_require__.O(result); | |||
| /******/ } | |||
| /******/ | |||
| /******/ var chunkLoadingGlobal = self["webpackChunk"] = self["webpackChunk"] || []; | |||
| /******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0)); | |||
| /******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal)); | |||
| /******/ })(); | |||
| /******/ | |||
| /************************************************************************/ | |||
| /******/ | |||
| /******/ // startup | |||
| /******/ // Load entry module and return exports | |||
| /******/ // This entry module depends on other loaded chunks and execution need to be delayed | |||
| /******/ __webpack_require__.O(undefined, ["public/css/index"], () => (__webpack_require__("./resources/js/index.js"))) | |||
| /******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["public/css/index"], () => (__webpack_require__("./resources/scss/index.scss"))) | |||
| /******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__); | |||
| /******/ | |||
| /******/ })() | |||
| ; | |||
| @ -0,0 +1,4 @@ | |||
| const Turbolinks = require('turbolinks') | |||
| Turbolinks.start() | |||
| Turbolinks.setProgressBarDelay(500) | |||
| @ -0,0 +1,5 @@ | |||
| .turbolinks-progress-bar { | |||
| width: 5px; | |||
| height: 100%; | |||
| background-color: blue; | |||
| } | |||
| @ -0,0 +1,55 @@ | |||
| <% layout('./../layout.html') %> | |||
| <div class="container"> | |||
| <div class="grid"> | |||
| <div class="col-12"> | |||
| <h2> | |||
| Create Bucket | |||
| </h2> | |||
| </div> | |||
| <div class="col-12"> | |||
| <form action="/bucket/store" method="POST" novalidate> | |||
| <div class="field"> | |||
| <label class="field__label"> | |||
| title* | |||
| <input class="field__text" name="title" type="text" /> | |||
| </label> | |||
| </div> | |||
| <div class="field"> | |||
| <label class="field__label"> | |||
| description* | |||
| <input class="field__text" name="description" type="text" /> | |||
| </label> | |||
| </div> | |||
| <div class="field"> | |||
| <label class="field__label"> | |||
| type* | |||
| <% it.types.forEach(function(type) { %> | |||
| <input class="field__choice" name="type" type="radio" value="<%= type.value %>" /> | |||
| <span class="field__help"> | |||
| <%= type %> | |||
| </span> | |||
| <% }) %> | |||
| </label> | |||
| </div> | |||
| <div class="field"> | |||
| <label class="field__label"> | |||
| visiblity* | |||
| <% it.visiblities.forEach(function(visiblity) { %> | |||
| <input class="field__choice" name="visiblity" type="radio" value="<%= visiblity.value %>" /> | |||
| <span> | |||
| <%= visiblity %> | |||
| </span> | |||
| <% }) %> | |||
| </label> | |||
| </div> | |||
| <div class=""> | |||
| <button class="button"> | |||
| Create | |||
| </button> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @ -0,0 +1,12 @@ | |||
| <% layout('./../layout.html') %> | |||
| <div class="container"> | |||
| <div class="grid"> | |||
| <div class="col-12"> | |||
| <h1><%= it.bucket.title %></h1> | |||
| <span> | |||
| <%= it.bucket.description %> | |||
| </span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @ -0,0 +1 @@ | |||
| 404 | |||
| @ -0,0 +1 @@ | |||
| ldjlsjfl | |||
| @ -1,24 +0,0 @@ | |||
| @extends('layout') | |||
| @section('main') | |||
| <div class="container"> | |||
| <h2> | |||
| Buckets | |||
| <button class="button"> | |||
| Create | |||
| </button> | |||
| </h2> | |||
| <h3> | |||
| </h3> | |||
| <app-buckets></app-buckets> | |||
| </div> | |||
| @push('scripts') | |||
| <script type="text/javascript" src="js/buckets.js"></script> | |||
| <script type="text/javascript" defer> | |||
| riot.mount('buckets', {!! json_encode([ 'buckets' => $buckets ]) !!}); | |||
| </script> | |||
| @endpush | |||
| @endsection | |||
| @ -0,0 +1,22 @@ | |||
| <% layout('./layout.html') %> | |||
| <div class="container"> | |||
| <div class="grid"> | |||
| <div class="col-12"> | |||
| <h2> | |||
| Buckets | |||
| <a class="button" href="/bucket/create"> | |||
| Create | |||
| </a> | |||
| </h2> | |||
| </div> | |||
| <h3> | |||
| Your Buckets | |||
| </h3> | |||
| <app-buckets visiblity="private"></app-buckets> | |||
| <h3> | |||
| Other Buckets | |||
| </h3> | |||
| <app-buckets visiblity="public,community"></app-buckets> | |||
| </div> | |||
| </div> | |||
| @ -1,55 +0,0 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> | |||
| <head> | |||
| <meta charset="utf-8"> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||
| <title>Nano Buckets</title> | |||
| @yield('head') | |||
| <link rel="stylesheet" href="css/app.css" /> | |||
| </head> | |||
| <body> | |||
| <header class="app-header"> | |||
| <div class="container is-fluid pt-2 pb-2"> | |||
| <nav class="navbar" role="navigation" aria-label="main navigation"> | |||
| <div class="navbar-brand"> | |||
| <a class="navbar-item" href="/"> | |||
| <img class="app-header__logo" src="/logo.svg" alt="Urban Filehub" /> | |||
| <span class="app-header__title ml-2"> | |||
| Filehub<strong>.Freifunk Minden</strong> | |||
| </span> | |||
| </a> | |||
| </div> | |||
| <div class="navbar-menu"> | |||
| <div class="navbar-start"> | |||
| <a class="navbar-item"> | |||
| Dashboard | |||
| </a> | |||
| </div> | |||
| </div> | |||
| </nav> | |||
| </div> | |||
| </header> | |||
| <section class="section"> | |||
| <div class="container is-fluid mt-3 mb-4"> | |||
| <urban-accordion> | |||
| <div title="Send me a Link"> | |||
| <urban-login-email></urban-login-email> | |||
| </div> | |||
| <div title="Login with Password"> | |||
| <urban-login-password></urban-login-password> | |||
| </div> | |||
| </urban-accordion> | |||
| </div> | |||
| </section> | |||
| <main> | |||
| @yield('main') | |||
| </main> | |||
| <script type="text/javascript" src="js/app.js"></script> | |||
| @stack('scripts') | |||
| </body> | |||
| </html> | |||
| @ -0,0 +1,31 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="utf-8"> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |||
| <title>Nano Buckets</title> | |||
| <link rel="stylesheet" href="/css/index.css" /> | |||
| <script type="text/javascript" src="/js/critical.js" defer></script> | |||
| </head> | |||
| <body> | |||
| <header class="app-header"> | |||
| <div class="container"> | |||
| <nav class="navbar" role="navigation" aria-label="main navigation"> | |||
| </nav> | |||
| </div> | |||
| </header> | |||
| <section class="app-section"> | |||
| <div class=""> | |||
| </div> | |||
| </section> | |||
| <main> | |||
| <%~ it.body %> | |||
| </main> | |||
| </body> | |||
| </html> | |||
| @ -0,0 +1,43 @@ | |||
| import 'https://deno.land/x/dotenv@v2.0.0/load.ts' | |||
| import { | |||
| opine, | |||
| serveStatic, | |||
| json, | |||
| urlencoded | |||
| } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||
| import { dirname, join, createError } from "https://deno.land/x/opine@1.5.3/deps.ts"; | |||
| import { renderFile } from 'https://deno.land/x/eta@v1.12.2/mod.ts' | |||
| // getting routes | |||
| import index from './src/http/index.ts' | |||
| import bucket from './src/http/bucket.ts' | |||
| import bucketApi from './src/http/api/bucket.ts' | |||
| const app = opine() | |||
| const __dirname = dirname(import.meta.url) | |||
| // | |||
| app.use(json()); // for parsing application/json | |||
| app.use(urlencoded()); // for parsing application/x-www-form-urlencoded | |||
| // adding static files | |||
| app.use(serveStatic(join(__dirname, 'public'))) | |||
| // adding eta as view engine | |||
| app.engine('.html', renderFile) | |||
| app.set('views', join(__dirname, 'resources/views')) | |||
| app.set('view engine', 'html') | |||
| // adding http classes for routes | |||
| app.use('/', index) | |||
| app.use('/bucket', bucket) | |||
| app.use('/api/bucket', bucketApi) | |||
| app.use((request, response, next) => { | |||
| response.setStatus(404) | |||
| response.render('errors/404') | |||
| }) | |||
| // let it rain | |||
| app.listen(Number(Deno.env.get('SERVER_PORT'))) | |||
| console.log('running on ' + Deno.env.get('SERVER_PORT')) | |||
| @ -0,0 +1,18 @@ | |||
| import Enum from 'https://deno.land/x/enum@v3.0.4/index.js' | |||
| // visibilties are a template for the roles | |||
| export const visibilties = new Enum([ | |||
| 'PUBLIC', | |||
| 'COMMUNITY', | |||
| 'PRIVATE' | |||
| ], { freeze: true, name: 'visibilties' }) | |||
| // types define the structure of a bucket | |||
| // kanban: columns with title | |||
| // masonry: wall with columns and each note can have different hight | |||
| // blog: all notes will be organized in one column | |||
| export const types = new Enum([ | |||
| 'KANBAN', | |||
| 'MASONRY', | |||
| 'BLOG' | |||
| ], { freeze: true, name: 'types' }) | |||
| @ -0,0 +1,49 @@ | |||
| import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||
| const router = Router() | |||
| /** | |||
| * | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.get('/:uuid', function(request, response) { | |||
| }) | |||
| /** | |||
| * | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.post('/', function(request, response, next) { | |||
| }) | |||
| /** | |||
| * | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.put('/:uuid', function(request, response, next) { | |||
| }) | |||
| /** | |||
| * | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.delete('/:uuid', function(request, response, next) { | |||
| }) | |||
| export default router | |||
| @ -0,0 +1,46 @@ | |||
| import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||
| const router = Router() | |||
| /** | |||
| * | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.post('/:bucket_id', function(request, response) | |||
| { | |||
| const [ valid, errors ] = await validate(body, { | |||
| title: [ maxLength(255) ], | |||
| content: [ maxLength(10922) ], | |||
| tags: [ ], | |||
| url: isUrl | |||
| }) | |||
| }) | |||
| /** | |||
| * | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.put('/:bucket_id/:id', function(request, response, next) | |||
| { | |||
| }) | |||
| /** | |||
| * | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.delete('/:bucket_id/:id', function(request, response, next) | |||
| { | |||
| }) | |||
| export default router | |||
| @ -0,0 +1,102 @@ | |||
| import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||
| import { v4 } from "https://deno.land/std@0.99.0/uuid/mod.ts"; | |||
| import { validate, required, isIn, maxLength } from 'https://deno.land/x/validasaur@v0.15.0/mod.ts' | |||
| import { Database } from 'https://deno.land/x/aloedb@0.9.0/mod.ts' | |||
| import { escapeHtml } from "https://deno.land/x/escape@1.3.0/mod.ts" | |||
| import { BucketSchema } from './../stores/bucket.ts' | |||
| import { visibilties, types } from './../enums/bucket.ts' | |||
| const router = Router() | |||
| /** | |||
| * render template for form | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.get('/create', function(request, response, next) | |||
| { | |||
| response.render('bucket/form', { | |||
| visiblities: visibilties.enums, | |||
| types: types.enums | |||
| }) | |||
| }) | |||
| /** | |||
| * render template for form | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.post('/store', async function(request, response, next) | |||
| { | |||
| const body = request.body | |||
| let typeValues = <any>[] | |||
| let visiblityValues = <any>[] | |||
| types.enums.forEach(function(type) { | |||
| typeValues.push(String(type.value)) | |||
| }) | |||
| visibilties.enums.forEach(function(visiblity) { | |||
| visiblityValues.push(String(visiblity.value)) | |||
| }) | |||
| // escape before validate | |||
| if (body.title) { | |||
| body.title = escapeHtml(body.title) | |||
| } | |||
| if (body.description) { | |||
| body.description = escapeHtml(body.description) | |||
| } | |||
| const [ valid, errors ] = await validate(body, { | |||
| title: [ required, maxLength(255) ], | |||
| description: [ required, maxLength(255) ], | |||
| type: [ required, isIn(typeValues) ], | |||
| visiblity: [ required, isIn(visiblityValues)] | |||
| }); | |||
| if (valid) { | |||
| const db = new Database<BucketSchema>('./storage/database/buckets.json') | |||
| body._id = v4.generate() | |||
| const bucket = await db.insertOne(body) | |||
| response.redirect('/bucket/' + bucket._id) | |||
| } else { | |||
| response.redirect('/bucket/create') | |||
| } | |||
| }) | |||
| /** | |||
| * render template for form | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.get('/:id', async function(request, response, next) | |||
| { | |||
| if (!v4.validate(request.params.id)) { | |||
| response.setStatus(404) | |||
| } | |||
| const db = new Database<BucketSchema>('./storage/database/buckets.json') | |||
| const bucket = await db.findOne({ '_id': request.params.id }) | |||
| if (!bucket) { | |||
| response.setStatus(404) | |||
| } | |||
| response.render('bucket/single', { | |||
| bucket: bucket | |||
| }) | |||
| }) | |||
| export default router | |||
| @ -0,0 +1,16 @@ | |||
| import { Router } from 'https://deno.land/x/opine@1.5.3/mod.ts' | |||
| const router = Router() | |||
| /** | |||
| * render template for form | |||
| * | |||
| * @param request | |||
| * @param response | |||
| * @return | |||
| */ | |||
| router.get('/', function(request, response, next) { | |||
| response.render('index') | |||
| }) | |||
| export default router | |||
| @ -0,0 +1,43 @@ | |||
| import { Drash } from 'https://deno.land/x/drash@v1.4.4/mod.ts' | |||
| import { v4 } from 'https://deno.land/std@0.99.0/uuid/mod.ts' | |||
| import { Bucket as BucketSchema } from './src/schemas/bucket.ts' | |||
| import Schema, { Type, string, number, array } from 'https://denoporter.sirjosh.workers.dev/v1/deno.land/x/computed_types/src/index.ts' | |||
| /** | |||
| * | |||
| * | |||
| */ | |||
| export class BucketResource extends Drash.Http.Resource | |||
| { | |||
| // route | |||
| static paths = ['/bucket/[:id?]'] | |||
| /** | |||
| * [GET description] | |||
| * @param id [description] | |||
| * @return [description] | |||
| */ | |||
| public GET(id) | |||
| { | |||
| const db = new Database<BucketSchema>() | |||
| const buckets = await db.findOne({ | |||
| '_id': id | |||
| }) | |||
| this.response.body = bucket | |||
| return this.response | |||
| } | |||
| /** | |||
| * | |||
| * | |||
| */ | |||
| public POST() | |||
| { | |||
| const db = new Database<BucketSchema>() | |||
| this.response.body = bucket | |||
| return this.response | |||
| } | |||
| } | |||
| @ -0,0 +1,24 @@ | |||
| import { Drash } from 'https://deno.land/x/drash@v1.4.4/mod.ts' | |||
| import { v4 } from 'https://deno.land/std@0.99.0/uuid/mod.ts' | |||
| import { Bucket as BucketSchema } from './src/schemas/bucket.ts' | |||
| /** | |||
| * | |||
| * | |||
| */ | |||
| export class BucketResource extends Drash.Http.Resource | |||
| { | |||
| // route | |||
| static paths = ['/buckets'] | |||
| // | |||
| public GET() | |||
| { | |||
| const db = new Database<BucketSchema>() | |||
| const buckets = await db.findMany() | |||
| this.response.body = buckets | |||
| return this.response | |||
| } | |||
| } | |||
| @ -0,0 +1,18 @@ | |||
| import { Drash } from 'https://deno.land/x/drash@v1.4.4/mod.ts' | |||
| /** | |||
| * | |||
| * | |||
| */ | |||
| export class IndexResource extends Drash.Http.Resource | |||
| { | |||
| // route | |||
| static paths = ['/'] | |||
| // | |||
| public GET() | |||
| { | |||
| this.response.body = 'Hallo' | |||
| return this.response | |||
| } | |||
| } | |||
| @ -0,0 +1,14 @@ | |||
| import { Database } from 'https://deno.land/x/aloedb/mod.ts'; | |||
| class BaseStore | |||
| { | |||
| construct() | |||
| { | |||
| this.db = new Database<('./storage/database/' + this.name + '.json') | |||
| } | |||
| uuid() | |||
| { | |||
| } | |||
| } | |||
| @ -0,0 +1,10 @@ | |||
| export interface BucketSchema { | |||
| _id: string; | |||
| title: string; | |||
| description: string; | |||
| owner: string; | |||
| configuration: string[]; | |||
| visiblity: string; | |||
| created_at: string; | |||
| updated_at: string; | |||
| } | |||
| @ -0,0 +1,8 @@ | |||
| export interface Note { | |||
| _id: string; | |||
| title: string; | |||
| type: string; | |||
| content: string; | |||
| attachment: array; | |||
| tags: string[]; | |||
| } | |||
| @ -0,0 +1,4 @@ | |||
| interface Tag { | |||
| _bucket_id: string; | |||
| name: string; | |||
| } | |||
| @ -0,0 +1,6 @@ | |||
| interface Bucket { | |||
| _id: string; | |||
| username: string; | |||
| password: string; | |||
| displayname: string; | |||
| } | |||
| @ -0,0 +1,13 @@ | |||
| import { validate, required, isNumber } from 'https://deno.land/x/validasaur@0.15.0/mod.ts' | |||
| // create shema for validation | |||
| const BucketSchema = Schema({ | |||
| title: string.trim().normalize(), | |||
| description: string.trim().normalize().optional(), | |||
| type: Schema.either('a', 'b', 'c'), | |||
| visiblity: Schema.either('a', 'b', 'c') | |||
| }) | |||
| // create type and get validator from schema | |||
| export type bucketType = Type<typeof BucketSchema> | |||
| export const bucketValidator = BucketSchema.destruct() | |||
| @ -0,0 +1,15 @@ | |||
| import Schema, { Type, string, number, array } from 'https://denoporter.sirjosh.workers.dev/v1/deno.land/x/computed_types/src/index.ts' | |||
| // create shema for validation | |||
| const NoteSchema = Schema({ | |||
| title: string.trim().normalize(), | |||
| description: string.trim().normalize().optional(), | |||
| type: Schema.either('a', 'b', 'c'), | |||
| visiblity: Schema.either('a', 'b', 'c') | |||
| }) | |||
| // create type and get validator from schema | |||
| type Note = Type<typeof NoteSchema> | |||
| const validator = NoteSchema.destruct() | |||
| export default validator | |||
| @ -0,0 +1,14 @@ | |||
| import Schema, { Type, string, number, array } from 'https://denoporter.sirjosh.workers.dev/v1/deno.land/x/computed_types/src/index.ts' | |||
| // create shema for validation | |||
| const UserSchema = Schema({ | |||
| username: string.trim().normalize(), | |||
| password: string.normalize(), | |||
| email: Schema.email() | |||
| }) | |||
| // create type and get validator from schema | |||
| type User = Type<typeof UserSchema> | |||
| const validator = UserSchema.destruct() | |||
| export default validator | |||
| @ -0,0 +1,23 @@ | |||
| const mix = require('laravel-mix') | |||
| /* | |||
| |-------------------------------------------------------------------------- | |||
| | Mix Asset Management | |||
| |-------------------------------------------------------------------------- | |||
| | | |||
| | Mix provides a clean, fluent API for defining some Webpack build steps | |||
| | for your Laravel application. By default, we are compiling the Sass | |||
| | file for the application as well as bundling up all the JS files. | |||
| | | |||
| */ | |||
| mix.options({ | |||
| terser: { | |||
| extractComments: false | |||
| } | |||
| }) | |||
| mix | |||
| .js('resources/js/index.js', 'public/js') | |||
| .js('resources/js/critical.js', 'public/js') | |||
| .sass('resources/scss/index.scss', 'public/css') | |||