Browse Source

Create Note object, simple database schema, and readonly web view

master
Skylar Ittner 7 months ago
parent
commit
841bf184f7
14 changed files with 317 additions and 98 deletions
  1. 2
    1
      .gitignore
  2. 1
    1
      app.php
  3. 4
    3
      composer.json
  4. 52
    7
      composer.lock
  5. BIN
      database.mwb
  6. 5
    0
      langs/en/notes.json
  7. 1
    1
      langs/en/titles.json
  8. 6
    0
      lib/Exceptions.lib.php
  9. 195
    0
      lib/Note.lib.php
  10. 1
    1
      nbproject/project.xml
  11. 2
    2
      pages.php
  12. 43
    1
      pages/home.php
  13. 3
    3
      settings.template.php
  14. 2
    78
      static/img/logo.svg

+ 2
- 1
.gitignore View File

@@ -1,4 +1,5 @@
1 1
 vendor
2 2
 settings.php
3 3
 nbproject/private
4
-*.sync-conflict*
4
+*.sync-conflict*
5
+*.bak

+ 1
- 1
app.php View File

@@ -114,7 +114,7 @@ END;
114 114
         // For mobile app
115 115
         echo "<script nonce=\"$SECURE_NONCE\">var navbar_breakpoint = \"$navbar_breakpoint\";</script>"
116 116
         ?>
117
-        <nav class="navbar navbar-expand-<?php echo $navbar_breakpoint; ?> navbar-dark bg-blue fixed-top">
117
+        <nav class="navbar navbar-expand-<?php echo $navbar_breakpoint; ?> navbar-dark bg-red fixed-top">
118 118
             <button class="navbar-toggler my-0 py-0" type="button" data-toggle="collapse" data-target="#navbar-collapse" aria-controls="navbar-collapse" aria-expanded="false" aria-label="Toggle navigation">
119 119
                 <!--<i class="fas fa-bars"></i>-->
120 120
                 <span class="navbar-toggler-icon"></span>

+ 4
- 3
composer.json View File

@@ -1,10 +1,11 @@
1 1
 {
2
-    "name": "netsyms/business-app-template",
3
-    "description": "Template for a webapp integrated with an AccountHub server.",
2
+    "name": "netsyms/notepost",
3
+    "description": "Note and list organizer.",
4 4
     "type": "project",
5 5
     "require": {
6 6
         "catfan/medoo": "^1.5",
7
-        "guzzlehttp/guzzle": "^6.2"
7
+        "guzzlehttp/guzzle": "^6.2",
8
+        "erusev/parsedown": "^1.7"
8 9
     },
9 10
     "license": "MPL-2.0",
10 11
     "authors": [

+ 52
- 7
composer.lock View File

@@ -4,8 +4,7 @@
4 4
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 5
         "This file is @generated automatically"
6 6
     ],
7
-    "hash": "5c7439c6e041764f2f6b0270a95ab3ae",
8
-    "content-hash": "e4e700119f47d2f68b0ed82abaf8c5c6",
7
+    "content-hash": "1aea304797149ba2b5bccc0f6d82c060",
9 8
     "packages": [
10 9
         {
11 10
             "name": "catfan/medoo",
@@ -64,7 +63,53 @@
64 63
                 "sql",
65 64
                 "sqlite"
66 65
             ],
67
-            "time": "2018-06-14 18:59:08"
66
+            "time": "2018-06-14T18:59:08+00:00"
67
+        },
68
+        {
69
+            "name": "erusev/parsedown",
70
+            "version": "1.7.1",
71
+            "source": {
72
+                "type": "git",
73
+                "url": "https://github.com/erusev/parsedown.git",
74
+                "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1"
75
+            },
76
+            "dist": {
77
+                "type": "zip",
78
+                "url": "https://api.github.com/repos/erusev/parsedown/zipball/92e9c27ba0e74b8b028b111d1b6f956a15c01fc1",
79
+                "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1",
80
+                "shasum": ""
81
+            },
82
+            "require": {
83
+                "ext-mbstring": "*",
84
+                "php": ">=5.3.0"
85
+            },
86
+            "require-dev": {
87
+                "phpunit/phpunit": "^4.8.35"
88
+            },
89
+            "type": "library",
90
+            "autoload": {
91
+                "psr-0": {
92
+                    "Parsedown": ""
93
+                }
94
+            },
95
+            "notification-url": "https://packagist.org/downloads/",
96
+            "license": [
97
+                "MIT"
98
+            ],
99
+            "authors": [
100
+                {
101
+                    "name": "Emanuil Rusev",
102
+                    "email": "hello@erusev.com",
103
+                    "homepage": "http://erusev.com"
104
+                }
105
+            ],
106
+            "description": "Parser for Markdown.",
107
+            "homepage": "http://parsedown.org",
108
+            "keywords": [
109
+                "markdown",
110
+                "parser"
111
+            ],
112
+            "time": "2018-03-08T01:11:30+00:00"
68 113
         },
69 114
         {
70 115
             "name": "guzzlehttp/guzzle",
@@ -129,7 +174,7 @@
129 174
                 "rest",
130 175
                 "web service"
131 176
             ],
132
-            "time": "2018-04-22 15:46:56"
177
+            "time": "2018-04-22T15:46:56+00:00"
133 178
         },
134 179
         {
135 180
             "name": "guzzlehttp/promises",
@@ -180,7 +225,7 @@
180 225
             "keywords": [
181 226
                 "promise"
182 227
             ],
183
-            "time": "2016-12-20 10:07:11"
228
+            "time": "2016-12-20T10:07:11+00:00"
184 229
         },
185 230
         {
186 231
             "name": "guzzlehttp/psr7",
@@ -245,7 +290,7 @@
245 290
                 "uri",
246 291
                 "url"
247 292
             ],
248
-            "time": "2017-03-20 17:10:46"
293
+            "time": "2017-03-20T17:10:46+00:00"
249 294
         },
250 295
         {
251 296
             "name": "psr/http-message",
@@ -295,7 +340,7 @@
295 340
                 "request",
296 341
                 "response"
297 342
             ],
298
-            "time": "2016-08-06 14:39:51"
343
+            "time": "2016-08-06T14:39:51+00:00"
299 344
         }
300 345
     ],
301 346
     "packages-dev": [],

BIN
database.mwb View File


+ 5
- 0
langs/en/notes.json View File

@@ -0,0 +1,5 @@
1
+{
2
+    "New": "New",
3
+    "Note": "Note",
4
+    "Edit": "Edit"
5
+}

+ 1
- 1
langs/en/titles.json View File

@@ -1,4 +1,4 @@
1 1
 {
2 2
     "home": "Home",
3
-    "test": "Test"
3
+    "Notes": "Notes"
4 4
 }

+ 6
- 0
lib/Exceptions.lib.php View File

@@ -10,4 +10,10 @@ class IncorrectPasswordException extends Exception {
10 10
     public function __construct(string $message = "Incorrect password.", int $code = 0, \Throwable $previous = null) {
11 11
         parent::__construct($message, $code, $previous);
12 12
     }
13
+}
14
+
15
+class NoSuchNoteException extends Exception {
16
+    public function __construct(string $message = "Note ID does not exist.", int $code = 0, \Throwable $previous = null) {
17
+        parent::__construct($message, $code, $previous);
18
+    }
13 19
 }

+ 195
- 0
lib/Note.lib.php View File

@@ -0,0 +1,195 @@
1
+<?php
2
+
3
+/*
4
+ * This Source Code Form is subject to the terms of the Mozilla Public
5
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
+ */
8
+
9
+class Note {
10
+
11
+    private $noteid;
12
+    private $ownerid;
13
+    private $content = "";
14
+    private $color = "FFFFFF";
15
+
16
+    /**
17
+     * Create a new Note object.
18
+     * @param string $content Note content in Markdown
19
+     * @param string $color Hex color "RRGGBB"
20
+     * @param int $ownerid The owner's user ID
21
+     */
22
+    public function __construct(string $content, string $color = "FFFFFF", int $ownerid = null, int $noteid = null) {
23
+        $this->content = $content;
24
+        $this->color = $color;
25
+        $this->ownerid = $ownerid;
26
+        $this->noteid = $noteid;
27
+    }
28
+
29
+    /**
30
+     * Load a note from the database and return it.
31
+     * @global type $database
32
+     * @param int $noteid
33
+     * @return \Note
34
+     * @throws NoSuchNoteException When the note ID isn't found.
35
+     */
36
+    public static function loadNote(int $noteid): Note {
37
+        global $database;
38
+
39
+        if (!$database->has('notes', ['noteid' => $noteid])) {
40
+            throw new NoSuchNoteException();
41
+        }
42
+
43
+        $notedata = $database->get('notes', ['noteid', 'ownerid', 'color', 'content'], ['noteid' => $noteid]);
44
+
45
+        return new Note($notedata['content'], $notedata['color'], $notedata['ownerid'], $notedata['noteid']);
46
+    }
47
+
48
+    /**
49
+     * Save the note to the database.
50
+     * @global type $database
51
+     * @param bool $saveas If true, save the note under a new ID.  Forced to
52
+     * true if the current note ID is missing or invalid.
53
+     * @return int The database ID of the saved note
54
+     * @throws Exception If there is no note owner set.
55
+     */
56
+    public function saveNote(bool $saveas = false): int {
57
+        global $database;
58
+
59
+        $data = [
60
+            'ownerid' => $this->ownerid,
61
+            'color' => $this->color,
62
+            'content' => $this->content
63
+        ];
64
+
65
+        // We can't UPDATE the database, so use save as for INSERT
66
+        if (empty($this->noteid) || !$database->has('notes', ['noteid' => $this->noteid])) {
67
+            $saveas = true;
68
+        }
69
+
70
+        if (empty($this->ownerid)) {
71
+            throw new Exception("No owner set.");
72
+        }
73
+
74
+        if ($saveas) {
75
+            $database->insert('notes', $data);
76
+            return $database->id();
77
+        } else {
78
+            $database->update('notes', $data, ['noteid' => $this->noteid]);
79
+            return $this->noteid;
80
+        }
81
+    }
82
+
83
+    /**
84
+     * Get the Markdown content of the note.
85
+     * @return string
86
+     */
87
+    public function getText(): string {
88
+        return $this->content;
89
+    }
90
+
91
+    /**
92
+     * Get the HTML render of the note.
93
+     * @param bool $fragment Get just the HTML content, instead of a whole HTML5 file
94
+     * @return string
95
+     */
96
+    public function getHTML(bool $fragment = true): string {
97
+        $parsedown = new Parsedown;
98
+        $parsedown->setSafeMode(true);
99
+        return $parsedown->text($this->content);
100
+    }
101
+
102
+    /**
103
+     * Get the note ID.
104
+     * @return int
105
+     */
106
+    public function getID(): int {
107
+        return $this->noteid;
108
+    }
109
+
110
+    /**
111
+     * Get the note color as RRGGBB hex.
112
+     * @return string
113
+     */
114
+    public function getColor(): string {
115
+        return $this->color;
116
+    }
117
+
118
+    /**
119
+     * Get the owner UID
120
+     * @return int
121
+     */
122
+    public function getOwnerID(): int {
123
+        return $this->ownerid;
124
+    }
125
+
126
+    /**
127
+     * Get the owner as a User object
128
+     * @return \User
129
+     */
130
+    public function getOwner(): User {
131
+        return new User($this->ownerid);
132
+    }
133
+
134
+    /**
135
+     * Set the note content
136
+     * @param string $markdown
137
+     */
138
+    public function setText(string $markdown) {
139
+        $this->content = $markdown;
140
+    }
141
+
142
+    /**
143
+     * Set the note color to a hex string
144
+     * @param string $color "RRGGBB"
145
+     */
146
+    public function setColor(string $color) {
147
+        $this->color = $color;
148
+    }
149
+
150
+    /**
151
+     * Set the owner by UID
152
+     * @param int $uid
153
+     */
154
+    public function setOwnerID(int $uid) {
155
+        $this->ownerid = $uid;
156
+    }
157
+
158
+    /**
159
+     * Set the owner
160
+     * @param User $user
161
+     */
162
+    public function setOwner(User $owner) {
163
+        $this->ownerid = $owner->getUID();
164
+    }
165
+
166
+    /**
167
+     * Get this note as an array.
168
+     * @return string
169
+     */
170
+    public function toArray(): array {
171
+        $owner = new User($this->ownerid);
172
+        $arr = [
173
+            'noteid' => $this->noteid,
174
+            'color' => $this->color,
175
+            'content' => $this->content,
176
+            'owner' => [
177
+                'uid' => $owner->getUID(),
178
+                'username' => $owner->getUsername(),
179
+                'name' => $owner->getName()
180
+            ]
181
+        ];
182
+
183
+        return $arr;
184
+    }
185
+
186
+    /**
187
+     * Read an array with the structure from toArray().
188
+     * @param array $arr
189
+     * @return \Note A Note constructed from the array data.
190
+     */
191
+    public static function fromArray(array $arr): Note {
192
+        return new Note($arr['content'], $arr['color'], $arr['owner']['uid'], $arr['noteid']);
193
+    }
194
+
195
+}

+ 1
- 1
nbproject/project.xml View File

@@ -3,7 +3,7 @@
3 3
     <type>org.netbeans.modules.php.project</type>
4 4
     <configuration>
5 5
         <data xmlns="http://www.netbeans.org/ns/php-project/1">
6
-            <name>BusinessAppTemplate</name>
6
+            <name>NotePost</name>
7 7
         </data>
8 8
     </configuration>
9 9
 </project>

+ 2
- 2
pages.php View File

@@ -7,9 +7,9 @@
7 7
 // List of pages and metadata
8 8
 define("PAGES", [
9 9
     "home" => [
10
-        "title" => "home",
10
+        "title" => "Notes",
11 11
         "navbar" => true,
12
-        "icon" => "fas fa-home"
12
+        "icon" => "far fa-sticky-note"
13 13
     ],
14 14
     "404" => [
15 15
         "title" => "404 error"

+ 43
- 1
pages/home.php View File

@@ -2,5 +2,47 @@
2 2
 /* This Source Code Form is subject to the terms of the Mozilla Public
3 3
  * License, v. 2.0. If a copy of the MPL was not distributed with this
4 4
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
+
6
+$noteids = $database->select('notes', 'noteid', ['ownerid' => $_SESSION['uid']]);
7
+
8
+$notes = [];
9
+
10
+foreach ($noteids as $n) {
11
+    $notes[] = Note::loadNote($n);
12
+}
5 13
 ?>
6
-<h1>Hello World</h1>
14
+
15
+<style nonce="<?php echo $SECURE_NONCE; ?>">
16
+<?php
17
+foreach ($notes as $note) {
18
+    echo "#notecard_" . $note->getID() . " {\n"
19
+            . "    background-color: #" . $note->getColor() . ";\n"
20
+            . "    border: 1px solid #" . $note->getColor() . ";\n"
21
+            . "}\n";
22
+}
23
+?>
24
+</style>
25
+
26
+<div class="row">
27
+
28
+    <?php
29
+    foreach ($notes as $note) {
30
+        ?>
31
+        <div class="col-12 col-sm-6 col-md-6 col-lg-4">
32
+            <div class="card" data-color="<?php echo $note->getColor(); ?>" id="notecard_<?php echo $note->getID(); ?>">
33
+                <div class="card-body">
34
+                    <?php echo $note->getHTML(); ?>
35
+                </div>
36
+
37
+                <div class="card-footer">
38
+                    <a href="" class="text-body">
39
+                        <i class="fas fa-edit"></i> <?php $Strings->get('Edit'); ?>
40
+                    </a>
41
+                </div>
42
+            </div>
43
+        </div>
44
+        <?php
45
+    }
46
+    ?>
47
+
48
+</div>

+ 3
- 3
settings.template.php View File

@@ -11,14 +11,14 @@ define("DEBUG", false);
11 11
 // Database connection settings
12 12
 // See http://medoo.in/api/new for info
13 13
 define("DB_TYPE", "mysql");
14
-define("DB_NAME", "app");
14
+define("DB_NAME", "notepost");
15 15
 define("DB_SERVER", "localhost");
16
-define("DB_USER", "app");
16
+define("DB_USER", "notepost");
17 17
 define("DB_PASS", "");
18 18
 define("DB_CHARSET", "utf8");
19 19
 
20 20
 // Name of the app.
21
-define("SITE_TITLE", "Web App Template");
21
+define("SITE_TITLE", "NotePost");
22 22
 
23 23
 
24 24
 // URL of the AccountHub API endpoint

+ 2
- 78
static/img/logo.svg View File

@@ -1,78 +1,2 @@
1
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
-
4
-<svg
5
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
6
-   xmlns:cc="http://creativecommons.org/ns#"
7
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8
-   xmlns:svg="http://www.w3.org/2000/svg"
9
-   xmlns="http://www.w3.org/2000/svg"
10
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12
-   width="512"
13
-   height="512"
14
-   viewBox="0 0 512.00001 512.00001"
15
-   id="svg2"
16
-   version="1.1"
17
-   inkscape:version="0.91 r13725"
18
-   sodipodi:docname="logo.svg"
19
-   inkscape:export-filename="/home/skylar/Documents/Projects/Sources/WebAppTemplate/static/img/logo.png"
20
-   inkscape:export-xdpi="90"
21
-   inkscape:export-ydpi="90">
22
-  <defs
23
-     id="defs4">
24
-    <inkscape:perspective
25
-       sodipodi:type="inkscape:persp3d"
26
-       inkscape:vp_x="-493.3276 : 245.89848 : 1"
27
-       inkscape:vp_y="0 : 1000 : 0"
28
-       inkscape:vp_z="464.45088 : 245.89848 : 1"
29
-       inkscape:persp3d-origin="-14.438371 : 160.56515 : 1"
30
-       id="perspective4236" />
31
-  </defs>
32
-  <sodipodi:namedview
33
-     id="base"
34
-     pagecolor="#ffffff"
35
-     bordercolor="#666666"
36
-     borderopacity="1.0"
37
-     inkscape:pageopacity="0.0"
38
-     inkscape:pageshadow="2"
39
-     inkscape:zoom="0.49497475"
40
-     inkscape:cx="-135.9681"
41
-     inkscape:cy="352.66131"
42
-     inkscape:document-units="px"
43
-     inkscape:current-layer="layer1"
44
-     showgrid="false"
45
-     units="px" />
46
-  <metadata
47
-     id="metadata7">
48
-    <rdf:RDF>
49
-      <cc:Work
50
-         rdf:about="">
51
-        <dc:format>image/svg+xml</dc:format>
52
-        <dc:type
53
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
54
-        <dc:title></dc:title>
55
-      </cc:Work>
56
-    </rdf:RDF>
57
-  </metadata>
58
-  <g
59
-     inkscape:label="Layer 1"
60
-     inkscape:groupmode="layer"
61
-     id="layer1"
62
-     transform="translate(0,-540.36216)">
63
-    <rect
64
-       style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.74509804"
65
-       id="rect4726"
66
-       width="512"
67
-       height="512"
68
-       x="0"
69
-       y="540.36218"
70
-       rx="50"
71
-       ry="50" />
72
-    <path
73
-       id="path4348"
74
-       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:9.87128067;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
75
-       d="m 132.93564,682.51771 213.96788,-43.14304 0,313.97496 -213.96788,-37.9643 z m 213.96788,-43.14304 0,313.97496 32.16084,-45.18373 0,-217.44396 z m -213.96788,43.14304 213.96788,-43.14304 32.16084,51.34727 -167.21823,22.47784 z m 78.91049,30.68207 167.21823,-22.47784 0,217.44396 -167.21823,-19.77968 z m -78.91049,-30.68207 0,232.86762 78.91049,-26.99911 0,-175.18644 z m 0,232.86762 213.96788,37.9643 32.16084,-45.18373 -167.21823,-19.77968 z"
76
-       inkscape:connector-curvature="0" />
77
-  </g>
78
-</svg>
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<svg width="512" height="512" version="1.1" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -540.36)"><rect y="540.36" width="512" height="512" rx="50" ry="50" fill="#fff"/><g stroke="#fff" stroke-width="7.7927"><rect x="233.35" y="641.56" width="233.78" height="233.78" rx="15.585" ry="15.585" fill="#ffeb3b"/><rect x="35.044" y="592.36" width="233.78" height="233.78" rx="15.585" ry="15.585" fill="#ef5350"/><rect x="113.35" y="755.34" width="233.78" height="233.78" rx="15.585" ry="15.585" fill="#ffeb3b"/></g></g></svg>

Loading…
Cancel
Save