commons-app / apps-android-commons

The Wikimedia Commons Android app allows users to upload pictures from their Android phone/tablet to Wikimedia Commons
https://commons-app.github.io/
Apache License 2.0
1.03k stars 1.24k forks source link

User-specific achievements failure #2603

Closed domdomegg closed 5 years ago

domdomegg commented 5 years ago

Summary:

Achievements fails to load for me, gives snackbar error "Something went wrong, We could not fetch your achievements".

Steps to reproduce:

How can we reproduce the issue?

See blank API response is particular to me: https://tools.wmflabs.org/urbanecmbot/commonsmisc/feedback.py?user=Domdomegg

Example correct API response (misaochan): https://tools.wmflabs.org/urbanecmbot/commonsmisc/feedback.py?user=Misaochan

{"articlesUsingImages": 83, "status": "ok", "featuredImages": {"Featured_pictures_on_Wikimedia_Commons": 0, "Quality_images": 0}, "user": "Misaochan", "deletedUploads": 76, "uniqueUsedImages": 73, "thanksReceived": 4, "imagesEditedBySomeoneElse": 231}

System logs:

2019-03-15 18:11:54.816 5911-5911/fr.free.nrw.commons E/AchievementsActivity: Fetching achievements statistics failed
    java.lang.NullPointerException: The callable returned a null value
        at io.reactivex.internal.functions.ObjectHelper.requireNonNull(ObjectHelper.java:39)
        at io.reactivex.internal.operators.single.SingleFromCallable.subscribeActual(SingleFromCallable.java:44)
        at io.reactivex.Single.subscribe(Single.java:3394)
        at com.tspoon.traceur.SingleOnAssembly.subscribeActual(SingleOnAssembly.java:43)
        at io.reactivex.Single.subscribe(Single.java:3394)
        at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
        at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:579)
        at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
        at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: com.tspoon.traceur.TraceurException: Debug Exception generated at call site
        at dalvik.system.VMStack.getThreadStackTrace(Native Method)
        at java.lang.Thread.getStackTrace(Thread.java:1538)
        at io.reactivex.Single.fromCallable(Single.java:580)
        at fr.free.nrw.commons.mwapi.OkHttpJsonApiClient.getAchievements(OkHttpJsonApiClient.java:118)
        at fr.free.nrw.commons.achievements.AchievementsActivity.setAchievements(AchievementsActivity.java:210)
        at fr.free.nrw.commons.achievements.AchievementsActivity.onCreate(AchievementsActivity.java:141)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: com.tspoon.traceur.TraceurException: Debug Exception generated at call site
        at dalvik.system.VMStack.getThreadStackTrace(Native Method)
        at java.lang.Thread.getStackTrace(Thread.java:1538)
        at io.reactivex.Single.subscribeOn(Single.java:3465)
        at fr.free.nrw.commons.achievements.AchievementsActivity.setAchievements(AchievementsActivity.java:211)
        at fr.free.nrw.commons.achievements.AchievementsActivity.onCreate(AchievementsActivity.java:141) 
        at android.app.Activity.performCreate(Activity.java:7136) 
        at android.app.Activity.performCreate(Activity.java:7127) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.app.ActivityThread.main(ActivityThread.java:6669) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
     Caused by: com.tspoon.traceur.TraceurException: Debug Exception generated at call site
        at dalvik.system.VMStack.getThreadStackTrace(Native Method)
        at java.lang.Thread.getStackTrace(Thread.java:1538)
        at io.reactivex.Single.observeOn(Single.java:2917)
        at fr.free.nrw.commons.achievements.AchievementsActivity.setAchievements(AchievementsActivity.java:212)
        at fr.free.nrw.commons.achievements.AchievementsActivity.onCreate(AchievementsActivity.java:141) 
        at android.app.Activity.performCreate(Activity.java:7136) 
        at android.app.Activity.performCreate(Activity.java:7127) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.app.ActivityThread.main(ActivityThread.java:6669) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 

Device and Android version:

2.10.1-debug-master~44c18ac23, emulator API level 28

Screen-shots:

Screenshot_1552673624

domdomegg commented 5 years ago

Pinging @urbanecm

urbanecm commented 5 years ago

Copying from server logs:

Traceback (most recent call last):
  File "/data/project/urbanecmbot/public_html//commonsmisc/feedback.py", line 132, in <module>
    print(jsonify(response))
  File "/data/project/urbanecmbot/public_html//commonsmisc/feedback.py", line 12, in jsonify
    return json.dumps(response)
  File "/usr/lib/python3.5/json/__init__.py", line 230, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python3.5/json/encoder.py", line 198, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.5/json/encoder.py", line 256, in iterencode
    return _iterencode(o, 0)
TypeError: keys must be a string

I've copied feedback.py to test.py and adapted it to use first argument passed on the command line instead of the user get parameter (which isn't easily passable from the commandline). Then I did the per-user testing @domdomegg did using the API, to confirm the error quoted above indeed comes from @domdomegg 's request (error.log seemingly doesn't log the url, just the traceback - an issue, but story for another task I guess).

tools.urbanecmbot@tools-sgebastion-07 ~/commonsmisc 
$ python3 test.py Domdomegg
Content-type: application/json

Printed without jsonify()
{'status': 'ok', 'uniqueUsedImages': 111, 'articlesUsingImages': 2741, 'deletedUploads': 19, 'thanksReceived': 13, 'user': 'Domdomegg', 'featuredImages': {'Quality_images': 0, b'Quality_images': 2, 'Featured_pictures_on_Wikimedia_Commons': 0}, 'imagesEditedBySomeoneElse': 318}
Traceback (most recent call last):
  File "test.py", line 108, in <module>
    print(jsonify(response))
  File "test.py", line 12, in jsonify
    return json.dumps(response)
  File "/usr/lib/python3.5/json/__init__.py", line 230, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python3.5/json/encoder.py", line 198, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.5/json/encoder.py", line 256, in iterencode
    return _iterencode(o, 0)
TypeError: keys must be a string
tools.urbanecmbot@tools-sgebastion-07 ~/commonsmisc 
$ python3 test.py Misaochan
Content-type: application/json

Printed without jsonify()
{'status': 'ok', 'deletedUploads': 76, 'user': 'Misaochan', 'imagesEditedBySomeoneElse': 231, 'articlesUsingImages': 83, 'thanksReceived': 4, 'uniqueUsedImages': 73, 'featuredImages': {'Quality_images': 0, 'Featured_pictures_on_Wikimedia_Commons': 0}}
{"status": "ok", "deletedUploads": 76, "user": "Misaochan", "imagesEditedBySomeoneElse": 231, "articlesUsingImages": 83, "thanksReceived": 4, "uniqueUsedImages": 73, "featuredImages": {"Quality_images": 0, "Featured_pictures_on_Wikimedia_Commons": 0}}

The interesting part is that for @domdomegg, there is Quality_images and b'Quality images' in the response variable, which certainly isn't correct. It matches the keys must be a string TypeError. That was caused by missing .decode('utf-8') statement in feedback.py. I've added it in commons-app/commonsmisc@63999a38b6c33f0e3fbe27a002bc4566e6d56407, API looks to be working again:

tools.urbanecmbot@tools-sgebastion-07 ~/commonsmisc 
$ curl 'https://tools.wmflabs.org/urbanecmbot/commonsmisc/feedback.py?user=Domdomegg'
{"thanksReceived": 13, "user": "Domdomegg", "imagesEditedBySomeoneElse": 318, "deletedUploads": 19, "featuredImages": {"Featured_pictures_on_Wikimedia_Commons": 0, "Quality_images": 2}, "uniqueUsedImages": 111, "articlesUsingImages": 2741, "status": "ok"}

Since I lack permissions to close this issue, please @domdomegg, check this and close if it works! Thanks!

domdomegg commented 5 years ago

Perfect, thanks for the quick fix :)