Overview
Comment:Log entities changes
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dev
Files: files | file ages | folders
SHA3-256: 5ac7bca013382783e7c944d1295c17291db6553da35a415806ff0cd19399c330
User & Date: bohwaz on 2022-09-06 02:29:46
Other Links: branch diff | manifest | tags
Context
2022-09-06
16:27
Implement user log check-in: bfc0704c53 user: bohwaz tags: dev
02:29
Log entities changes check-in: 5ac7bca013 user: bohwaz tags: dev
02:28
Fix User object when loading from session for the first time set the properties to null check-in: 06ddf4afcc user: bohwaz tags: dev
Changes

Modified src/include/data/1.2.0_schema.sql from [99e642cb57] to [f2956189b4].

159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    id_user INTEGER NULL REFERENCES users (id) ON DELETE CASCADE,
    expiry INT NOT NULL
);

CREATE TABLE IF NOT EXISTS logs
(
    id INTEGER NOT NULL PRIMARY KEY,
    id_user INTEGER NULL REFERENCES users (id),
    type INTEGER NOT NULL,
    details TEXT NULL,
    created TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(created) IS NOT NULL AND datetime(created) = created),
    ip_address TEXT NULL
);

CREATE INDEX IF NOT EXISTS logs_ip ON logs (ip_address, created);







|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    id_user INTEGER NULL REFERENCES users (id) ON DELETE CASCADE,
    expiry INT NOT NULL
);

CREATE TABLE IF NOT EXISTS logs
(
    id INTEGER NOT NULL PRIMARY KEY,
    id_user INTEGER NULL REFERENCES users (id) ON DELETE CASCADE,
    type INTEGER NOT NULL,
    details TEXT NULL,
    created TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP CHECK (datetime(created) IS NOT NULL AND datetime(created) = created),
    ip_address TEXT NULL
);

CREATE INDEX IF NOT EXISTS logs_ip ON logs (ip_address, created);

Modified src/include/lib/Garradin/Entity.php from [0c0151fd71] to [14002be8a9].

82
83
84
85
86
87
88







89
90
91
92
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107
108
109
110
111
112


113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	// Add plugin signals to save/delete
	public function save(bool $selfcheck = true): bool
	{
		$name = get_class($this);
		$name = str_replace('Garradin\Entities\\', '', $name);
		$name = 'entity.' . $name . '.save';








		// Specific entity signal
		if (Plugin::fireSignal($name . '.before', ['entity' => $this])) {
			return true;
		}

		// Generic entity signal
		if (Plugin::fireSignal('entity.save.before', ['entity' => $this])) {
			return true;
		}

		$return = parent::save($selfcheck);

		Plugin::fireSignal($name . '.after', ['entity' => $this, 'success' => $return]);

		Plugin::fireSignal('entity.save.after', ['entity' => $this, 'success' => $return]);

		return $return;
	}

	public function delete(): bool
	{
		$name = get_class($this);
		$name = str_replace('Garradin\Entities\\', '', $name);
		$name = 'entity.' . $name . '.delete';



		if (Plugin::fireSignal($name . '.before', ['entity' => $this])) {
			return true;
		}

		// Generic entity signal
		if (Plugin::fireSignal('entity.delete.before', ['entity' => $this])) {
			return true;
		}

		$return = parent::delete();
		Plugin::fireSignal($name . '.after', ['entity' => $this, 'success' => $return]);
		Plugin::fireSignal('entity.delete.after', ['entity' => $this, 'success' => $return]);

		return $return;
	}
}







>
>
>
>
>
>
>

|




|



|
>
|

|










>
>
|




|




|
|




82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
	// Add plugin signals to save/delete
	public function save(bool $selfcheck = true): bool
	{
		$name = get_class($this);
		$name = str_replace('Garradin\Entities\\', '', $name);
		$name = 'entity.' . $name . '.save';

		// We are doing selfcheck here before sending the before event
		if ($selfcheck) {
			$this->selfCheck();
		}

		$new = $this->exists() ? false : true;

		// Specific entity signal
		if (Plugin::fireSignal($name . '.before', ['entity' => $this, 'new' => $new])) {
			return true;
		}

		// Generic entity signal
		if (Plugin::fireSignal('entity.save.before', ['entity' => $this, 'new' => $new])) {
			return true;
		}

		$return = parent::save(false);

		Plugin::fireSignal($name . '.after', ['entity' => $this, 'success' => $return, 'new' => $new]);

		Plugin::fireSignal('entity.save.after', ['entity' => $this, 'success' => $return, 'new' => $new]);

		return $return;
	}

	public function delete(): bool
	{
		$name = get_class($this);
		$name = str_replace('Garradin\Entities\\', '', $name);
		$name = 'entity.' . $name . '.delete';

		$id = $this->id();

		if (Plugin::fireSignal($name . '.before', ['entity' => $this, 'id' => $id])) {
			return true;
		}

		// Generic entity signal
		if (Plugin::fireSignal('entity.delete.before', ['entity' => $this, 'id' => $id])) {
			return true;
		}

		$return = parent::delete();
		Plugin::fireSignal($name . '.after', ['entity' => $this, 'success' => $return, 'id' => $id]);
		Plugin::fireSignal('entity.delete.after', ['entity' => $this, 'success' => $return, 'id' => $id]);

		return $return;
	}
}

Modified src/include/lib/Garradin/Log.php from [7f7b3d84f8] to [a52c5b5578].

1
2
3
4
5
6

7
8
9
10
11
12
13
<?php

namespace Garradin;

use Garradin\Config;
use Garradin\DB;


class Log
{
	/**
	 * How many seconds in the past should we look for failed attempts?
	 * @type int
	 */






>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

namespace Garradin;

use Garradin\Config;
use Garradin\DB;
use Garradin\Users\Session;

class Log
{
	/**
	 * How many seconds in the past should we look for failed attempts?
	 * @type int
	 */
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
		self::LOGIN_REMIND => 'Rappel de mot de passe',
		self::LOGIN_CHANGE => 'Modification de mot de passe',
		self::DELETE => 'Suppression',
		self::CREATE => 'Création',
		self::EDIT => 'Modification',
	];

	static public function add(int $type, ?string $details = null): void
	{
		if ($type != LOGIN_FAIL) {
			$keep = Config::getInstance()->log_retention;

			// Don't log anything
			if ($keep == 0) {
				return;
			}
		}

		$ip = Utils::getIP();
		$session = Session::getInstance();
		$id_user = $session->isLogged() ? $session->getUser()->id : null;

		DB::getInstance()->insert('log', [
			'id_user'    => $user_id,
			'type'       => $type,
			'details'    => $details,
			'ip_address' => $ip,
		]);
	}

	static public function clean(): void
	{
		$config = Config::getInstance();







|

|












|
|

|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
		self::LOGIN_REMIND => 'Rappel de mot de passe',
		self::LOGIN_CHANGE => 'Modification de mot de passe',
		self::DELETE => 'Suppression',
		self::CREATE => 'Création',
		self::EDIT => 'Modification',
	];

	static public function add(int $type, ?array $details = null): void
	{
		if ($type != self::LOGIN_FAIL) {
			$keep = Config::getInstance()->log_retention;

			// Don't log anything
			if ($keep == 0) {
				return;
			}
		}

		$ip = Utils::getIP();
		$session = Session::getInstance();
		$id_user = $session->isLogged() ? $session->getUser()->id : null;

		DB::getInstance()->insert('logs', [
			'id_user'    => $id_user,
			'type'       => $type,
			'details'    => $details ? json_encode($details) : null,
			'ip_address' => $ip,
		]);
	}

	static public function clean(): void
	{
		$config = Config::getInstance();

Modified src/include/lib/Garradin/Plugin.php from [d3e8f17634] to [46dad6af40].

731
732
733
734
735
736
737












738
739
740
741
742
743
744
	 * FALSE si des plugins ont été appelés mais aucun n'a stoppé l'exécution
	 */
	static public function fireSignal($signal, $params = null, &$callback_return = null)
	{
		if (!self::$signals) {
			return null;
		}













		// Process SYSTEM_SIGNALS first
		foreach (SYSTEM_SIGNALS as $system_signal) {
			if (key($system_signal) != $signal) {
				continue;
			}








>
>
>
>
>
>
>
>
>
>
>
>







731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
	 * FALSE si des plugins ont été appelés mais aucun n'a stoppé l'exécution
	 */
	static public function fireSignal($signal, $params = null, &$callback_return = null)
	{
		if (!self::$signals) {
			return null;
		}

		// Log events
		if (0 === strpos($signal, 'entity.') && isset($params['entity'])) {
			$type = str_replace(__NAMESPACE__ . '\Entities\\', '', get_class($params['entity']));

			if ($signal == 'entity.delete.after') {
				Log::add(Log::DELETE, ['entity' => $type, 'id' => $params['id'] ?? null]);
			}
			elseif ($signal == 'entity.save.after') {
				Log::add(!empty($params['new']) ? Log::CREATE : Log::EDIT, ['entity' => $type, 'id' => $params['entity']->id()]);
			}
		}

		// Process SYSTEM_SIGNALS first
		foreach (SYSTEM_SIGNALS as $system_signal) {
			if (key($system_signal) != $signal) {
				continue;
			}

Modified src/include/lib/Garradin/Users/DynamicFields.php from [9078c00c8f] to [6047200630].

634
635
636
637
638
639
640




641
642
643
644
645
646
647
				UPDATE users SET is_parent = 1 WHERE id = NEW.id_parent;
			END;
			CREATE TRIGGER %1$s_parent_trigger_delete AFTER DELETE ON %1$s BEGIN
				SELECT CASE WHEN OLD.id_parent IS NULL THEN RAISE(IGNORE) ELSE 0 END;
				-- Set is_parent to 0 if user has no longer any children
				UPDATE %1$s SET is_parent = 0 WHERE id = OLD.id_parent
					AND 0 = (SELECT COUNT(*) FROM users WHERE id_parent = OLD.id_parent);




			END;', $table_name));
	}

	/**
	 * Enregistre les changements de champs en base de données
	 */
	public function rebuildUsersTable(array $fields): void







>
>
>
>







634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
				UPDATE users SET is_parent = 1 WHERE id = NEW.id_parent;
			END;
			CREATE TRIGGER %1$s_parent_trigger_delete AFTER DELETE ON %1$s BEGIN
				SELECT CASE WHEN OLD.id_parent IS NULL THEN RAISE(IGNORE) ELSE 0 END;
				-- Set is_parent to 0 if user has no longer any children
				UPDATE %1$s SET is_parent = 0 WHERE id = OLD.id_parent
					AND 0 = (SELECT COUNT(*) FROM users WHERE id_parent = OLD.id_parent);
			END;
			-- Keep logs for create/delete/edit actions, just make them anonymous
			CREATE TRIGGER %1$s_delete_logs BEFORE DELETE ON users BEGIN
			    UPDATE logs SET id_user = NULL WHERE id_user = OLD.id AND type >= 10;
			END;', $table_name));
	}

	/**
	 * Enregistre les changements de champs en base de données
	 */
	public function rebuildUsersTable(array $fields): void