Perhaps I'm missing something in the API, but there doesn't seem to be a method to completely delete an achievement and existing unlocks.

Scenario;
Say we have a course node type and related to this course node type we have several achievements. Now in the future after several users have achieved some of the achievements against a specific course, the course is now outdated or no longer available. The course is then deleted from the system. To avoid leaving cruft in the database I would want to also remove said achivement unlocks.

The best I have come up with is to iterate over the corresponding achievements calling achievements_locked() for each user that has achieved said achievement. This is very time consuming and generally needs to be handled via batch processing. It would be great to have an equivalent of achievements_user_delete(), but for achievement ids.

Is there any interest in this functionality?

Comments

morbus iff’s picture

Yeah, I can see the use-case for this.

Perhaps achievements_delete($achievement_id), which does (pseudo here, untested):

* Loads the achievement info for $achievement_id.
* Finds all uids from achievement_unlocks that has $achievement_id.
* db_delete all uid + $achievement_id from achievement_unlocks.
* db_update all uid + $achievement_id in achievement_totals with points - $points.
* db_delete all uids in achievement_totals with 0 points. [1]

[1] This is for the edge-case where a user ONLY has one unlock and it just so happens to be the achievement we're deleting. Subtracting the points from the user in achievement_totals would give them 0 points, in which case, they've no real reason to be in the achievement_totals list. This, of course, presumes that you don't have any "negative" achievements which subtract points from users (which, IMO, is a bad thing).

Although, hrm, this doesn't handle the "previous unlock" problem - that is, if a user has 100 unlocks, and their latest was "achievement we're deleting", we have to set their new latest to the achievement they earned before "achievement we're deleting". I suppose there needs to be another bit of logic something like:

* Find all uids from achievement_totals that has $achievement_id in .achievement_id.
* For each one, figure out their new unlock and set it.

You could do the above in three SQL statements (i.e., finding all the uids, finding all the uids' last unlock, setting all the new unlocks) as opposed to the per-user that achievement_locked does.

Anyways, just thinking aloud. I'd be supportive of this functionality.

What site is this for? Would love to check it out.

jgraham’s picture

Morbus thanks for the fast response!

I was thinking of something similar to what you detailed above but missed the edge case you flagged for achievement_totals. Your pseudo code is a great start.

I'll work up a patch that implements what you have above, and post here for review.

jgraham’s picture

Status: Active » Needs review
StatusFileSize
new2.33 KB

Attached patch implements the logic as described above.

Also this site has not launched yet, otherwise I would/could provide you a link.

ambot112’s picture

Issue summary: View changes
StatusFileSize
new2.46 KB

The points can be 0, while the achievement is null.