diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/class/art2.php | 3 | ||||
-rw-r--r-- | app/class/controllerart.php | 76 | ||||
-rw-r--r-- | app/class/controllerconnect.php | 36 | ||||
-rw-r--r-- | app/class/controllerhome.php | 5 | ||||
-rw-r--r-- | app/class/controllertimeline.php | 56 | ||||
-rw-r--r-- | app/class/dbitem.php | 32 | ||||
-rw-r--r-- | app/class/event.php | 156 | ||||
-rw-r--r-- | app/class/modeltimeline.php | 139 | ||||
-rw-r--r-- | app/class/routes.php | 7 | ||||
-rw-r--r-- | app/view/templates/backtopbar.php | 2 | ||||
-rw-r--r-- | app/view/templates/connect.php | 4 | ||||
-rw-r--r-- | app/view/templates/navart.php | 2 | ||||
-rw-r--r-- | app/view/templates/timeline.php | 90 |
13 files changed, 554 insertions, 54 deletions
diff --git a/app/class/art2.php b/app/class/art2.php index 2341ff9..a7e94f3 100644 --- a/app/class/art2.php +++ b/app/class/art2.php @@ -44,9 +44,6 @@ class Art2 const LEN = 255; const LENTEXT = 2**20; const SECUREMAX = 2; - const LENCOULEUR = 7; - const DEBUT = '(?id='; - const FIN = ')'; const TABS = ['main', 'css', 'header', 'body', 'nav', 'aside', 'footer', 'javascript']; const VAR_DATE = ['date', 'datecreation', 'datemodif', 'daterender']; diff --git a/app/class/controllerart.php b/app/class/controllerart.php index 00b7558..20ef634 100644 --- a/app/class/controllerart.php +++ b/app/class/controllerart.php @@ -33,13 +33,19 @@ class Controllerart extends Controller public function importart() { - $art = $this->artmanager->get($this->art); + if (isset($_SESSION['artupdate']) && $_SESSION['artupdate']['id'] == $this->art->id()) { + $art = new Art2($_SESSION['artupdate']); + unset($_SESSION['artupdate']); + } else { + $art = $this->artmanager->get($this->art); + } if ($art !== false) { $this->art = $art; return true; } else { return false; } + } @@ -104,9 +110,9 @@ class Controllerart extends Controller } else { $page = ['head' => $this->art->renderhead(), 'body' => $this->art->renderbody()]; } - if($canread) { + if ($canread) { $this->art->addaffcount(); - if($this->user->level() < 2) { + if ($this->user->level() < 2) { $this->art->addvisitcount(); } } @@ -208,40 +214,56 @@ class Controllerart extends Controller public function update($id) { $this->setart($id, 'artupdate'); - $_SESSION['workspace']['showrightpanel'] = isset($_POST['workspace']['showrightpanel']); - $_SESSION['workspace']['showleftpanel'] = isset($_POST['workspace']['showleftpanel']); - - if (!empty($_POST['fontsize']) && $_POST['fontsize'] !== Config::fontsize()) { - Config::setfontsize($_POST['fontsize']); - Config::savejson(); - } - + $this->movepanels(); + $this->fontsize(); $date = new DateTimeImmutable($_POST['pdate'] . $_POST['ptime'], new DateTimeZone('Europe/Paris')); $date = ['date' => $date]; - if ($this->importart() && $this->canedit()) { + if ($this->importart()) { + if ($this->canedit()) { + + // Check if someone esle edited the page during the editing. + $oldart = clone $this->art; + $this->art->hydrate($_POST); - $oldart = clone $this->art; - $this->art->hydrate($_POST); + if (self::COMBINE && $_POST['thisdatemodif'] === $oldart->datemodif('string')) { - if (self::COMBINE) { - if ($_POST['thisdatemodif'] === $oldart->datemodif('string')) { - $compare = $this->artmanager->combine($this->art, $oldart); - if (!empty($compare['diff'])) { - $this->art->hydrate($compare['mergeart']); - } } - } - $this->art->hydrate($date); - $this->art->updateedited(); - $this->art->addauthor($this->user->id()); - $this->artmanager->update($this->art); - $this->routedirect('artedit', ['art' => $this->art->id()]); - + $this->art->hydrate($date); + $this->art->updateedited(); + $this->art->addauthor($this->user->id()); + + + $this->artmanager->update($this->art); + + $this->routedirect('artedit', ['art' => $this->art->id()]); + //$this->showtemplate('updatemerge', $compare); + } else { + // If the editor session finished during the editing, let's try to reconnect to save the editing + $_SESSION['artupdate'] = $_POST; + $_SESSION['artupdate']['id'] = $this->art->id(); + $this->routedirect('connect'); + } + + } + $this->routedirect('art'); + } + + public function movepanels() + { + $_SESSION['workspace']['showrightpanel'] = isset($_POST['workspace']['showrightpanel']); + $_SESSION['workspace']['showleftpanel'] = isset($_POST['workspace']['showleftpanel']); + } + + public function fontsize() + { + if (!empty($_POST['fontsize']) && $_POST['fontsize'] !== Config::fontsize()) { + Config::setfontsize($_POST['fontsize']); + Config::savejson(); } } diff --git a/app/class/controllerconnect.php b/app/class/controllerconnect.php index 5328447..d6aa7a2 100644 --- a/app/class/controllerconnect.php +++ b/app/class/controllerconnect.php @@ -6,31 +6,33 @@ class Controllerconnect extends Controller public function log() { if (isset($_POST['log'])) { - if (isset($_POST['id'])) { - $id = $_POST['id']; - } else { - $id = null; - } + $id = $_POST['id'] ?? null; + $route = $_POST['route'] ?? 'home'; if ($_POST['log'] === 'login') { - $this->login($id); + $this->login($route, $id); } elseif ($_POST['log'] === 'logout') { - $this->logout($id); + $this->logout($route, $id); } } - } public function connect() { - $this->showtemplate('connect', []); + if(isset($_SESSION['artupdate'])) { + $artupdate['route'] = 'artedit'; + $artupdate['id'] = $_SESSION['artupdate']['id']; + } else { + $artupdate = [$route = 'home']; + } + $this->showtemplate('connect', $artupdate); } - public function login($id) + public function login($route, $id = null) { if (isset($_POST['pass'])) { $this->user = $this->usermanager->passwordcheck($_POST['pass']); @@ -41,21 +43,21 @@ class Controllerconnect extends Controller } } - if (!empty($id)) { - $this->routedirect('artread/', ['art' => $id]); + if ($id !== null) { + $this->routedirect($route, ['art' => $id]); } else { - $this->routedirect('home'); + $this->routedirect($route); } } - public function logout($id) + public function logout($route, $id = null) { $this->user = $this->usermanager->logout(); $this->usermanager->writesession($this->user); - if (!empty($id)) { - $this->routedirect('artread/', ['art' => $id]); + if ($id !== null && $route !== 'home') { + $this->routedirect($route, ['art' => $id]); } else { - $this->routedirect('home'); + $this->routedirect($route); } } diff --git a/app/class/controllerhome.php b/app/class/controllerhome.php index caeb652..f5b3068 100644 --- a/app/class/controllerhome.php +++ b/app/class/controllerhome.php @@ -17,11 +17,6 @@ class Controllerhome extends Controller public function desktop() { - $this->table2(); - } - - public function table2() - { $table = $this->modelhome->getlister(); $this->opt = $this->modelhome->optinit($table); diff --git a/app/class/controllertimeline.php b/app/class/controllertimeline.php new file mode 100644 index 0000000..7e617e1 --- /dev/null +++ b/app/class/controllertimeline.php @@ -0,0 +1,56 @@ +<?php + +class Controllertimeline extends Controller +{ + /** + * @var Modeltimeline + */ + protected $eventmanager; + + public function __construct($render) { + parent::__construct($render); + $this->eventmanager = new Modeltimeline; + } + + public function desktop() + { + $eventlist = $this->eventmanager->showlast(['message'], 100, 0); + + $groupedeventlist = $this->eventmanager->group($eventlist); + + $this->showtemplate('timeline', ['eventlist' => $eventlist, 'groupedeventlist' => $groupedeventlist]); + + } + + public function add() + { + if($this->user->level() >= Modeluser::EDITOR && !empty($_POST['message'])) { + + $event = new Event($_POST); + $event->stamp(); + $event->setid($this->eventmanager->getlastfreeid()); + $this->eventmanager->add($event); + } + $this->routedirect('timeline'); + } + + public function clap() + { + if(isset($_POST['id']) && isset($_POST['clap'])) { + $event = $this->eventmanager->get(intval($_POST['id'])); + $event->addclap(); + $this->eventmanager->add($event); + } + $this->routedirect('timeline'); + + } +} + + + + + + + + +?>
\ No newline at end of file diff --git a/app/class/dbitem.php b/app/class/dbitem.php new file mode 100644 index 0000000..2035316 --- /dev/null +++ b/app/class/dbitem.php @@ -0,0 +1,32 @@ +<?php + +class Dbitem +{ + public function hydrate($datas) + { + foreach ($datas as $key => $value) { + $method = 'set' . $key; + + if (method_exists($this, $method)) { + $this->$method($value); + } + } + + } + + public function dry() + { + $array = []; + foreach (get_object_vars($this) as $var => $value) { + if (in_array($var, $this::VAR_DATE)) { + $array[$var] = $this->$var('string'); + } else { + $array[$var] = $this->$var(); + } + } + return $array; + } +} + + +?>
\ No newline at end of file diff --git a/app/class/event.php b/app/class/event.php new file mode 100644 index 0000000..9fc75d2 --- /dev/null +++ b/app/class/event.php @@ -0,0 +1,156 @@ +<?php + +class Event extends Dbitem +{ + protected $id; + protected $date; + protected $type; + protected $user; + protected $target; + protected $message; + protected $clap = 0; + + const EVENT_TYPES = ['message', 'art_add', 'art_edit', 'art_delete', 'media_add', 'media_delete', 'font_add']; + const EVENT_BASE = ['message']; + const EVENT_ART = ['art_add', 'art_edit', 'art_delete']; + const EVENT_MEDIA = ['media_add', 'media_delete']; + const EVENT_FONT = ['font_add', 'font_delete']; + const MESSAGE_MAX_LENGTH = 2 ** 10; + + const VAR_DATE = ['date']; + + public function __construct($datas) + { + $this->hydrate($datas); + } + + public function stamp() + { + $this->date = new DateTimeImmutable(null, timezone_open("Europe/Paris")); + $this->user = idclean($this->user); + if (in_array($this->type, self::EVENT_ART)) { + $this->target = idclean($this->target); + } elseif ($this->type === 'message') { + $this->message = htmlspecialchars($this->message); + } + } + + public function addclap() + { + $this->clap ++; + } + + // _____________________ G E T __________________________ + + public function id() + { + return $this->id; + } + + public function date($type = 'datetime') + { + switch ($type) { + case 'datetime': + return $this->date; + break; + + case 'string': + return $this->date->format(DateTime::ISO8601); + break; + + case 'hrdi': + $now = new DateTimeImmutable(null, timezone_open("Europe/Paris")); + return hrdi($this->date->diff($now)); + break; + + } + } + + public function type() + { + return $this->type; + } + + public function user() + { + return $this->user; + } + + public function target() + { + return $this->target; + } + + public function message() + { + return $this->message; + } + + public function clap() + { + return $this->clap; + } + + + + // ________________________ S E T ____________________ + + public function setid($id) + { + if (is_int($id)) { + $this->id = $id; + } + } + + public function setdate($date) + { + if ($date instanceof DateTimeImmutable) { + $this->date = $date; + } elseif (is_string($date)) { + $this->date = DateTimeImmutable::createFromFormat(DateTime::ISO8601, $date, new DateTimeZone('Europe/Paris')); + } + } + + public function settype($type) + { + if (in_array($type, self::EVENT_TYPES)) { + $this->type = $type; + } + } + + public function setuser($user) + { + if (is_string($user) && strlen($user) < Model::MAX_ID_LENGTH) { + $this->user = $user; + } + } + + public function settarget($target) + { + if (is_string($target) && strlen($target) < Model::MAX_ID_LENGTH) { + $this->target = $target; + } + } + + public function setmessage($message) + { + if (is_string($message) && strlen($message) < self::MESSAGE_MAX_LENGTH) { + $this->message = $message; + } + } + + public function setclap($clap) + { + if(is_int($clap)) { + $this->clap = $clap; + } + } + + + + + +} + + +?>
\ No newline at end of file diff --git a/app/class/modeltimeline.php b/app/class/modeltimeline.php new file mode 100644 index 0000000..b575dda --- /dev/null +++ b/app/class/modeltimeline.php @@ -0,0 +1,139 @@ +<?php + +class Modeltimeline extends Modeldb +{ + const EVENT_BASE = ['message']; + const EVENT_ART = ['art_add', 'art_edit', 'art_delete']; + const EVENT_MEDIA = ['media_add', 'media_delete']; + const EVENT_FONT = ['font_add', 'font_delete']; + + public function __construct() + { + parent::__construct(); + $this->storeinit('timeline'); + } + + public function get(int $id) + { + $eventdata = $this->repo->findById($id); + if ($eventdata !== false) { + return new Event($eventdata); + } else { + return false; + } + } + + /** + * Retrun a list of Event objects + * + * @return array array of Event where the key is the Event id. + */ + public function getlister() : array + { + $eventlist = []; + $datalist = $this->repo->findAll(); + foreach ($datalist as $eventdata) { + $event = new Event($eventdata); + $id = intval($event->id()); + $eventlist[$id] = $event; + } + return $eventlist; + } + + + public function getlisterid(array $idlist = []) : array + { + $eventdatalist = $this->repo->query() + ->where('__id', 'IN', $idlist) + ->execute(); + + $eventlist = []; + foreach ($eventdatalist as $id => $eventdata) { + $eventlist[$id] = new Event($eventdata); + } + return $eventlist; + } + + + /** + * Store event + * + * @param Event The event to be stored in the repositery + * + * @return bool retrun true if it works, false if it fails + */ + public function add(Event $event) : bool + { + $eventdata = new \JamesMoss\Flywheel\Document($event->dry()); + $eventdata->setId($event->id()); + $result = $this->repo->store($eventdata); + return $result; + } + + /** + * Return last free id + * + * @return int id + */ + public function getlastfreeid() : int + { + $idlist = $this->list(); + + if (!empty($idlist)) { + $id = max($idlist); + $id++; + } else { + $id = 1; + } + return $id; + } + + public function group(array $events) + { + $id = 0; + $subid = 0; + $lastuser = null; + foreach ($events as $event) { + if($event->user() !== $lastuser) { + $subid = 0; + $id ++; + $groupedevents[$id]['user'] = $event->user(); + } else { + $subid ++; + } + $groupedevents[$id][$subid] = $event; + $lastuser = $event->user(); + } + return $groupedevents; + } + + public function showlast(array $types, int $qty = 25, int $offset = 0) + { + $types = array_intersect($types, $this->types()); + + $eventdatalist = $this->repo->query() + ->where('type', 'IN', $types) + ->orderBy('date DESC') + ->limit($qty, $offset) + ->execute(); + + $eventlist = []; + foreach ($eventdatalist as $id => $eventdata) { + $eventlist[] = new Event($eventdata); + } + + $eventlist = array_reverse($eventlist); + return $eventlist; + } + + + public function types() + { + return array_merge(self::EVENT_ART, self::EVENT_BASE, self::EVENT_MEDIA, self::EVENT_MEDIA); + } + + +} + + +?>
\ No newline at end of file diff --git a/app/class/routes.php b/app/class/routes.php index a72d2e9..2ccc269 100644 --- a/app/class/routes.php +++ b/app/class/routes.php @@ -22,14 +22,17 @@ class Routes ['POST', '/!media/upload', 'Controllermedia#upload', 'mediaupload'], ['POST', '/!media/folder', 'Controllermedia#folder', 'mediafolder'], ['GET', '/!font', 'Controllerfont#desktop', 'font'], + ['GET', '/!font/render', 'Controllerfont#render', 'fontrender'], + ['POST', '/!font/add', 'Controllerfont#add', 'fontadd'], ['POST', '/!admin', 'Controlleradmin#update', 'adminupdate'], ['GET', '/!admin', 'Controlleradmin#desktop', 'admin'], ['GET', '/!user', 'Controlleruser#desktop', 'user'], ['POST', '/!user/add', 'Controlleruser#add', 'useradd'], ['POST', '/!user/update', 'Controlleruser#update', 'userupdate'], ['GET', '/!info', 'Controllerinfo#desktop', 'info'], - ['GET', '/!font/render', 'Controllerfont#render', 'fontrender'], - ['POST', '/!font/add', 'Controllerfont#add', 'fontadd'], + ['GET', '/!timeline', 'Controllertimeline#desktop', 'timeline'], + ['POST', '/!timeline/add', 'Controllertimeline#add', 'timelineadd'], + ['POST', '/!timeline/clap', 'Controllertimeline#clap', 'timelineclap'], ['GET', '/[cid:art]/', 'Controllerart#read', 'artread/'], ['GET', '/[cid:art]', 'Controllerart#read', 'artread'], ['GET', '/[cid:art]/add', 'Controllerart#add', 'artadd'], diff --git a/app/view/templates/backtopbar.php b/app/view/templates/backtopbar.php index 78e9181..d6b522e 100644 --- a/app/view/templates/backtopbar.php +++ b/app/view/templates/backtopbar.php @@ -15,6 +15,7 @@ <form action="<?= $this->url('log') ?>" method="post" id="connect"> <input type="password" name="pass" id="loginpass" placeholder="password"> +<input type="hidden" name="route" value="home"> <input type="submit" name="log" value="login"> </form> @@ -22,6 +23,7 @@ <?php } else { ?> <span> +<a href="<?= $this->url('timeline') ?>" <?= $tab == 'timeline' ? 'class="actualpage"' : '' ?>>timeline</a> <a href="<?= $this->url('user') ?>" <?= $tab == 'user' ? 'class="actualpage"' : '' ?>><?= $user->id() ?></a> <i><?= $user->level() ?></i> </span> diff --git a/app/view/templates/connect.php b/app/view/templates/connect.php index 06fe9c8..5d7ee5c 100644 --- a/app/view/templates/connect.php +++ b/app/view/templates/connect.php @@ -11,7 +11,11 @@ <?php if($user->isvisitor()) { ?> +<?= $route === 'artedit' ? '<p>Your edits have been temporary saved. You need to connect and update to store it completly</p>' : '' ?> + <form action="<?= $this->url('log') ?>" method="post"> +<input type="hidden" name="route" value="<?= $route ?>"> +<input type="hidden" name="id" value="<?= $id ?>"> <input type="password" name="pass" id="loginpass" placeholder="password"> <input name="log" type="submit" value="login"> </form> diff --git a/app/view/templates/navart.php b/app/view/templates/navart.php index be3b248..1e6b551 100644 --- a/app/view/templates/navart.php +++ b/app/view/templates/navart.php @@ -72,6 +72,7 @@ <li class="drop"> <form action="<?= $this->url('log') ?>" method="post"> <input type="password" name="pass" id="loginpass" placeholder="password"> + <input type="hidden" name="route" value="artread/"> <input type="hidden" name="id" value="<?= $art->id() ?>"> <input type="submit" name="log" value="login" id="button"> </form> @@ -82,6 +83,7 @@ <li class="drop"> <form action="<?= $this->url('log') ?>" method="post"> <input type="hidden" name="id" value="<?= $art->id() ?>"> + <input type="hidden" name="route" value="artread/"> <input type="submit" name="log" value="logout" id="button"> </form> </li> diff --git a/app/view/templates/timeline.php b/app/view/templates/timeline.php new file mode 100644 index 0000000..fcf8afd --- /dev/null +++ b/app/view/templates/timeline.php @@ -0,0 +1,90 @@ +<?php $this->layout('layout', ['title' => 'timeline', 'css' => $css . 'home.css', 'favicon' => '']) ?> + + + + +<?php $this->start('page') ?> + + +<body> + + <?php $this->insert('backtopbar', ['user' => $user, 'tab' => 'timeline']) ?> + +<?php if($user->iseditor()) { ?> + +<main class="timeline"> + +<h1>Timeline</h1> + +<ul> + +<?php +foreach ($groupedeventlist as $eventuser) { + + if($user->id() === $eventuser['user']) { + $class = 'class="self user"'; + } else { + $class = 'class="user"'; + } + echo '<li '. $class .'>'; + echo '<h3>'. $eventuser['user'] .'</h3>'; + echo' <ul>'; + foreach ($eventuser as $key => $event) { + if($key !== 'user') { + echo '<li class="event">'; + switch ($event->type()) { + case 'message': + echo '<p class="eline">'. $event->message() .'</p>'; + break; + } + + ?> + + + <?= !empty($event->clap()) ? '<b class="eline">'. $event->clap() .'</b>' : '' ?> + + <span class="details"> + + <?php if($user->id() !== $eventuser['user']) {?> + <form class="eline" method="post" action="<?= $this->url('timelineclap') ?>"> + <input type="hidden" name="id" value="<?= $event->id() ?>"> + <input type="submit" name="clap" value="👌"> + </form> + <?php } ?> + + + <i class="eline"><?= $event->date('hrdi') ?> ago</i> + + </span> + + </li> + + <?php + } + } + echo '</ul></li>'; +} +?> + +</ul> + +<form action="<?= $this->url('timelineadd') ?>" method="post"> + +<input type="hidden" name="type" value="message"> + +<input type="hidden" name="user" value="<?= $user->id() ?>"> + +<label for="message">message</label> +<textarea name="message" id="message" cols="30" rows="10" autofocus></textarea> +<input type="submit" value="send"> +</form> + +</main> + +<?php } ?> + +</body> + + + +<?php $this->stop() ?>
\ No newline at end of file |