Skip to content

Commit 29fefe0

Browse files
committed
WIP simplification of api
1 parent 35949ed commit 29fefe0

File tree

4 files changed

+66
-96
lines changed

4 files changed

+66
-96
lines changed

classes/local/tag/tag_manager.php

+56-88
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ public static function is_tagging_enabled_and_supported(): bool {
7878
return $enabledinconfig && $supportedbyfs;
7979
}
8080

81+
// TODO unit tests for this functionality
82+
public static function can_override_existing_tags(): bool {
83+
return !empty(get_config('tool_objectfs', 'overridetags'));
84+
}
85+
8186
/**
8287
* Gathers the tag values for a given content hash
8388
* @param string $contenthash
@@ -98,41 +103,6 @@ private static function gather_tags(string $contenthash): array {
98103
return $tags;
99104
}
100105

101-
/**
102-
* Returns the tags stored locally in the DB for the given file contenthash
103-
* @param int $objectid
104-
* @return array array of key=>value pairs, the tags for the given file that are stored in the database.
105-
*/
106-
public static function query_local_tags(string $contenthash): array {
107-
global $DB;
108-
$records = $DB->get_records('tool_objectfs_object_tags', ['contenthash' => $contenthash], '', 'tagkey,tagvalue');
109-
110-
$tags = [];
111-
foreach ($records as $record) {
112-
$tags[$record->tagkey] = $record->tagvalue;
113-
}
114-
return $tags;
115-
}
116-
117-
/**
118-
* Synchronises the tags for a given file.
119-
*
120-
* @param string $contenthash file to update tags for
121-
* @param bool $force By default, will not update stored tags unless the gathered tags differ from the locally stored tags. If this is true, it will always store the newest tags.
122-
*/
123-
public static function update_tags_if_necessary(string $contenthash, bool $force = false) {
124-
// Gather the exact current and compare against local db.
125-
$gatheredtags = self::gather_tags($contenthash);
126-
$localtags = self::query_local_tags($contenthash);
127-
128-
// Update if forced to, or if what we just gathered is not the same as what is stored in the database.
129-
$shouldupdate = $force || self::are_tags_different($gatheredtags, $localtags);
130-
131-
if ($shouldupdate) {
132-
self::store_tags($contenthash, $gatheredtags);
133-
}
134-
}
135-
136106
/**
137107
* Updates the local db tag records, and marks object as needing sync to sync local tags to external.
138108
* @param int $objectid
@@ -141,39 +111,23 @@ public static function update_tags_if_necessary(string $contenthash, bool $force
141111
private static function store_tags(string $contenthash, array $tags) {
142112
global $DB;
143113

144-
// Get a lock, since we are modifying the tags in the DB.
145-
$lock = self::get_object_tag_lock($contenthash);
146-
147-
if (!$lock) {
148-
throw new coding_exception("Unable to obtain lock for object " . $contenthash); // TODO different ex type ?
149-
}
150-
151-
try {
152-
// Purge any existing tags for this object.
153-
$DB->delete_records('tool_objectfs_object_tags', ['contenthash' => $contenthash]);
154-
155-
// Record time in var, so that they all have the same time.
156-
$timemodified = time();
157-
158-
// Store new records.
159-
$recordstostore = [];
160-
foreach ($tags as $key => $value) {
161-
$recordstostore[] = [
162-
'contenthash' => $contenthash,
163-
'tagkey' => $key,
164-
'tagvalue' => $value,
165-
'timemodified' => $timemodified
166-
];
167-
}
168-
$DB->insert_records('tool_objectfs_object_tags', $recordstostore);
169-
170-
// We always mark them needing sync after changing the values.
171-
self::mark_object_tag_sync_status($contenthash, self::SYNC_STATUS_NEEDS_SYNC);
172-
} catch (Exception $e) {
173-
// Failed - release lock and rethrow.
174-
$lock->release();
175-
throw $e;
114+
// Purge any existing tags for this object.
115+
$DB->delete_records('tool_objectfs_object_tags', ['contenthash' => $contenthash]);
116+
117+
// Record time in var, so that they all have the same time.
118+
$timemodified = time();
119+
120+
// Store new records.
121+
$recordstostore = [];
122+
foreach ($tags as $key => $value) {
123+
$recordstostore[] = [
124+
'contenthash' => $contenthash,
125+
'tagkey' => $key,
126+
'tagvalue' => $value,
127+
'timemodified' => $timemodified
128+
];
176129
}
130+
$DB->insert_records('tool_objectfs_object_tags', $recordstostore);
177131
}
178132

179133
/**
@@ -188,15 +142,19 @@ public static function get_objects_needing_sync(int $limit) {
188142
[$insql, $inparams] = $DB->get_in_or_equal([OBJECT_LOCATION_DUPLICATED, OBJECT_LOCATION_EXTERNAL, OBJECT_LOCATION_ORPHANED], SQL_PARAMS_NAMED);
189143
$inparams['syncstatus'] = self::SYNC_STATUS_NEEDS_SYNC;
190144

145+
// TODO somehow exclude ones already queued ?
191146
$records = $DB->get_records_select('tool_objectfs_objects', 'tagsyncstatus = :syncstatus AND location ' . $insql, $inparams, '', 'contenthash', 0, $limit);
192147
return array_column($records, 'contenthash');
193148
}
194149

195150
/**
196-
* Replicates the tags stored locally in the DB for a given object to the external object store.
151+
* Gathers the tag values for a given object contenthash, stores the values in the DB and then replicates these to the external store.
152+
* Will mark the object sync status to sync status not required.
197153
* @param string $contenthash
198154
*/
199-
public static function replicate_local_to_external_tags_for_object(string $contenthash) {
155+
public static function calculate_tags_store_locally_and_replicate_to_external(string $contenthash) {
156+
// TODO someway to genericise this, so we can call it with and without replicating ,etc...
157+
200158
// Take lock, to ensure tags are not updated while we sync them.
201159
$lock = self::get_object_tag_lock($contenthash);
202160

@@ -205,18 +163,24 @@ public static function replicate_local_to_external_tags_for_object(string $conte
205163
}
206164

207165
try {
208-
// TODO refactor so all func use contenthash, no objectid.
209-
// Then also probably remove from DB.
210-
$tags = self::query_local_tags($contenthash);
211-
212-
// Get current client.
166+
// Get current client, ensure it is configured correctly.
213167
$client = manager::get_client(manager::get_objectfs_config());
214168

215169
if (empty($client)) {
216170
throw new coding_exception("No client set, cannot replicate tags"); // TODO moodle ex ?
217171
}
218172

219-
$client->set_object_tags($contenthash, $tags);
173+
// Sanity check, ensure supports object tagging.
174+
if (!$client->supports_object_tagging()) {
175+
throw new coding_exception("Client does not support object tagging"); // TODO different ex ?
176+
}
177+
178+
// Gather tags from sources & store locally.
179+
$gatheredtags = self::gather_tags($contenthash);
180+
self::store_tags($contenthash, $gatheredtags);
181+
182+
// Replicate to external.
183+
$client->set_object_tags($contenthash, $gatheredtags);
220184

221185
// Mark as synced, this stops it from re-syncing in the future.
222186
self::mark_object_tag_sync_status($contenthash, self::SYNC_STATUS_SYNC_NOT_REQUIRED);
@@ -226,6 +190,23 @@ public static function replicate_local_to_external_tags_for_object(string $conte
226190
}
227191
}
228192

193+
/**
194+
* This should only ever be called as part of uploading an object for the first time.
195+
*/
196+
public static function calculate_tags_and_store_locally_and_return(string $contenthash): array {
197+
// TODO.
198+
}
199+
200+
private static function should_set_object_tags(string $contenthash) {
201+
// If can override, always return true.
202+
if (self::can_override_existing_tags()) {
203+
return true;
204+
}
205+
206+
// Else lookup if object already has tags, or if it even exists.
207+
// TODO.
208+
}
209+
229210
/**
230211
* Gets a tag writing lock on the given object, ensuring tags are not written/updated while being synced, for example.
231212
* @param string $contenthash
@@ -249,17 +230,4 @@ private static function mark_object_tag_sync_status(string $contenthash, int $st
249230
}
250231
$DB->set_field('tool_objectfs_objects', 'tagsyncstatus', $status, ['contenthash' => $contenthash]);
251232
}
252-
253-
/**
254-
* Returns true if the tags given are different. They are different when their keys or values do not match, order does not matter.
255-
* @param array $a array of key=>value where keys and values are both strings
256-
* @param array $b array of key=>value where keys and values are both strings
257-
* @return bool
258-
*/
259-
private static function are_tags_different(array $a, array $b): bool {
260-
// Order the keys in both arrays, then do a simple equality check.
261-
ksort($a);
262-
ksort($b);
263-
return $a !== $b;
264-
}
265233
}

classes/task/update_object_tags.php

+1-5
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@ public function execute() {
4545
return;
4646
}
4747

48-
// Update local tags in db.
49-
tag_manager::update_tags_if_necessary($contenthash);
50-
51-
// Sync these to external store.
52-
tag_manager::replicate_local_to_external_tags_for_object($contenthash);
48+
tag_manager::calculate_tags_store_locally_and_replicate_to_external($contenthash);
5349
}
5450
}

lang/en/tool_objectfs.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,6 @@
278278
$string['check:tagging:ok'] = 'Object tagging ok';
279279
$string['check:tagging:error'] = 'Error trying to tag object';
280280
$string['settings:maxtaggingperrun'] = 'Max objects tagged per run';
281-
$string['settings:maxtaggingperrun:desc'] = 'The maximum number of objects to be queued for tag updates per run of the queue_objects_needing_tags scheduled task.';
281+
$string['settings:maxtaggingperrun:desc'] = 'The maximum number of objects to be queued for tag updates per run of the queue_objects_needing_tags scheduled task.';
282+
$string['settings:overridetags'] = 'Override existing object tags';
283+
$string['settings:overridetags:desc'] = 'If enabled, ObjectFS will override any existing object tags as needed. If disabled and object already has tags, they will be left untouched. Primarily for use in situations where multiple environments target the same storage bucket. Generally, you will enable this in production, but disable everywhere else. See the README for more information.';

settings.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,17 @@
255255
new lang_string('settings:taggingheader', 'tool_objectfs'), ''));
256256

257257
// TODO some info here about tagging, maybe a link to doc in git.
258-
259258
$settings->add(new admin_setting_configcheckbox('tool_objectfs/taggingenabled',
260-
new lang_string('settings:taggingenabled', 'tool_objectfs'), '', ''));
259+
new lang_string('settings:taggingenabled', 'tool_objectfs'), '', 0));
261260

262261
$settings->add(new admin_setting_configtext('tool_objectfs/maxtaggingperrun',
263262
new lang_string('settings:maxtaggingperrun', 'tool_objectfs'),
264263
get_string('settings:maxtaggingperrun:desc', 'tool_objectfs'),
265264
10000,
266265
PARAM_INT));
266+
267+
$settings->add(new admin_setting_configcheckbox('tool_objectfs/overridetags',
268+
new lang_string('settings:overridetags', 'tool_objectfs'),
269+
get_string('settings:overridetags:desc', 'tool_objectfs'),
270+
1));
267271
}

0 commit comments

Comments
 (0)