This is quite a patch. I started writing some tests for the admin UI and while doing that, noticed that the current points aren't updated when a transaction is edited after already being approved.

Additionally, I the current max_points implementation is wrong because it is a sum of all positive points transactions, not the highest number of messages a user ever had.

So what this patch does:

- Implement all kind of checks regarding editing transactions for points, status and category changes. Expired (will remove the need for expiry transactions) and author will follow later.

- Re-implements the max_points implementation to only update it when the current_points would actually be higher than max points. Difference to the current implementation: Imagine 3 point transactions, +10, -3, +4. With the old implementation, max_points was 14 and with the new one, it is 11.

- While writing tests for the above bugfix, I noted that the get_max_points() also was implemented incorrectly and returned the overall max_points instead of a specific category. Fixed too.

- To make testing easier, I added the final $params array in userpoints_userpointsapi() to the array that is returned. This is an alternative to the patch at #441678: Use drupal_write_record(). Needed to be able to import transactions with migrate_extras, this solution however only extends the api instead of changing and will therefore not break anything.

- Added comprehensive tests for the above fixes, all kinds of status/category/points combinations are verified.

- Started adding tests for the administrative UI. These will be extended later to cover the different permissions and settings.

Happy testing :)

CommentFileSizeAuthor
fix_edit_max_with_tests.patch19.13 KBberdir

Comments

BenK’s picture

Subscribing and will test! :-)

BenK’s picture

Status: Needs review » Needs work

Berdir,

Wow... what a great catch and what a great patch. The work you did seems rock solid. I tried to trick the system with changes from positive to negative points, category changes, and status changes (approved, pending, etc.)... sometimes all at the same time. And I couldn't fool the system. It came out right every time.

I also tested out the max_points implementation by using your suggestion of debug(userpoints_get_max_points($uid, $category_id)); in the devel php window. I added and subtracted lots of points amounts. From what I can tell, max_points is working terrifically now. I wasn't quite sure how to test max_points for all categories (since "General" isn't actually a category and using "0" doesn't seem to to work). But if you let me know how, I can test that, too.

So the only "bug" I found was something you already knew: Problems with point totals involving expired transactions. More specifically, I took a points transaction that was declined and expired... and I changed it to approved (it was still expired). I found that the user was awarded points, but he shouldn't have been because the approved points were already expired.

So you want to tackle expiration in this patch or postpone to a follow up patch? If we're not going to do expiration now, then this patch is a huge improvement and RTBC. Really great work on this!

--Ben

berdir’s picture

Status: Needs work » Fixed

As discussed, commited the patch.

BenK’s picture

Status: Fixed » Needs work

I just tested the actual 7.x-1.x branch and everything is working great... except for one thing that could be addressed in a follow up patch.

It appears there is something wrong with the max_points logic for 'all' categories. To test, I had 1,098 points in all categories before I began my testing. Initially, the max_points were at 1,100. So I added 5,000 points to set a new max_points in all categories. But instead of showing 6,098 as my max points (which was also the total that showed on the transactions page), I showed 6,150 as my max_points.

So somehow max_points is overstating the actual max_points when computing it for all categories. (Max_points for individual categories are working great.)

--Ben

P.S. To test max_points, I've now been executing the following commands from the devel module PHP execution window:

General category max_points (for user #2): debug(userpoints_get_max_points(2, 0)); or debug(userpoints_get_max_points(2));

Taxonomy term 2 max_points (for user #2): debug(userpoints_get_max_points(2, 2));

All categories max_points (for user #2): debug(userpoints_get_max_points(2, 'all'));

These commands seem to work fine. Thanks for the explanation.

BenK’s picture

Also, did you already solve the expiration bug in the committed patch? From what I've just tested, it seems like the bug related to "getting points for changes to expired transactions" has already been fixed. :-)

--Ben

berdir’s picture

I haven't done any changes so the bug either still exists or never did :) I think, it should have never existed but then again, I haven't tested that part.

I can't reproduce the max_points issue, though.

Can you try to create a reproducable way with a user that did not have any points before? Because whatever old data already exists might be wrong already so it's hard to reproduce based on that.

Also, try to select the rows for that user where it is currently wrong directly from the database.

Something like this query should work:

SELECT * FROM userpoints WHERE uid = %d

Replace %d with the user id. You can for example execute this in phpmyadmin. Then look at the rows which are returned, check the max_points of all categories there, change something and then look again :)

BenK’s picture

Hey Berdir,

I've finally isolated why the max_points seems wrong when computing it for all categories. Your suggestion of looking at the data in phpmyadmin was very helpful.

Basically, I think I might disagree with the logic of how max_points is calculated for all categories (it is fine for individual categories). Here's the problem: max_points for all categories appears to be a simple sum of the max_points for each individual category. But because the max_points for each individual category did not occur at the same moment in time, it tends to overstate how many points a user actually had at any one time.

So here's why this was confusing. I was adding 5,000 points to a user (an absurdly large number of points just to make sure it was the highest point total they ever had) and then was expecting the current "all" categories point total to equal the max_points for all categories (since I had just added enough points to make it their highest point total ever). But the current point total was always smaller than the max_points. This is because the user had slightly higher totals previously in the other categories (even though they never had anywhere this number of points before).

So I thought max_points for all categories would equal the user's highest lifetime point total. But this isn't actually the case.

So the problem is how do we fix this? We want to know the highest point total (across all categories) that the user has ever had. Is there any way to compute this? Or is the only way to know this to actually save a new "highest lifetime points" field for each user?

Don't want to create more work for us than is really needed...

Hope this makes sense,
Ben

BenK’s picture

I also determined that the expiration issue I previously noticed still occurs. But it also stems from a mistaken understanding of the system's current logic. The question is whether we should change the logic.

Basically, when adding an expiration date in the past to a points transaction, I expected the user to immediately lose those points because the expiration date has already happened. But the system is only designed to consider that expiration date once cron had been run. (I wasn't running cron on this -dev server.) Once I manually hit the cron button, then a new expiration transaction occurred and the points were deducted.

So the question is whether we want to continue to do these "expiry" transactions on cron or if we instead want to create an "expired" status on the original transaction. If we do the second option, then we would also need a way for setting the expiration date to immediately trigger a status change (and thus a reduction in points) if the expiration date occurred in the past.

Not quite sure what to do with this... thoughts?

--Ben

berdir’s picture

Status: Needs work » Fixed

#7 There is absolutely no way to compute this. Can you please open a separate issue for this? Sounds like we actually need to store the total max_points. Maybe we could do that for the normal points too for performance reasons (and views integrations reasons, would make that huge issue re: displaying total points in views much easier). Not sure yet about that.

#8 Same here, please open a separate issue. There are several things that need to be done and discussed here.

Closing this issue, let's continue with incremental steps in new issues.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

hakankahraman66’s picture

I loaded userpoints 7.x-1.0-beta1.
I get the following notice info.

Notice: Undefined index: points in userpoints_userpointsapi() (line 551 of /path/sites/all/modules/userpoints/userpoints.module).

I am not able to load dev version and any patches. I get service from Web Sevice Provider, so they do not allow me to run drush.
Drupal update does not allow to upgrade to dev version.
Could you release beta2.
Thank you.