Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Branch for working on gitcoin bounty https://gitcoin.co/issue/gitcoinco/web/5339/3562 #5979

Closed
wants to merge 31 commits into from

Conversation

cervoneluca
Copy link

Description

Modified the model and the quests creation form in order to allow a new quest style.
The work is related to the following bounty on gitcoin.

https://gitcoin.co/issue/gitcoinco/web/5339/3562

Refers/Fixes

Refs: #5339

Testing

This commit is mostly to create the new branch so a test is not needed

Added the new quest type to the quests creation form
@codecov
Copy link

codecov bot commented Feb 12, 2020

Codecov Report

Merging #5979 into master will increase coverage by <.01%.
The diff coverage is 22.22%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #5979      +/-   ##
==========================================
+ Coverage   27.56%   27.57%   +<.01%     
==========================================
  Files         282      283       +1     
  Lines       26148    26245      +97     
  Branches     3850     3865      +15     
==========================================
+ Hits         7208     7236      +28     
- Misses      18675    18744      +69     
  Partials      265      265
Impacted Files Coverage Δ
app/quests/helpers.py 20% <ø> (ø) ⬆️
app/quests/views.py 16.17% <11.11%> (-0.13%) ⬇️
app/quests/quest_types/code_battle_style.py 26.31% <26.31%> (ø)
app/quests/models.py 39.89% <7.14%> (-2.27%) ⬇️
app/dashboard/embed.py 31.6% <0%> (+3.44%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e59cceb...d0f05fd. Read the comment docs.

…de battle style.

- Modified the template file new.html
- Modified the javascript in order to make it possible to chooe among quests types. If users choose the Code Battle quest type, the business logic to add and handle question is modified
…ugs too: 1. the tooltip were not added to new questions; 2. the remove question buttons did not work properly
@cervoneluca
Copy link
Author

Query to insert a test quest

--
-- Data for Name: quests_quest; Type: TABLE DATA; Schema: public; Owner: postgres
--

COPY quests_quest (id, created_on, modified_on, title, description, game_schema, game_metadata, kudos_reward_id, questions, cooldown_minutes, visible, difficulty, style, creator_id, value, background, ui_data, edit_comments, unlocked_by_hackathon_id, unlocked_by_quest_id) FROM stdin;
58	2020-02-15 09:35:15+00	2020-02-15 10:18:24.986955+00	The Javascript Code Battle	This is a code battle quest. You will need to know how to write a javascript function. You will be prompted with a set of quiz on javascript functions. If you demonstrate to have proper skills, then you'll fight a final Boss by writing your own function!	{"intro": "This is a code battle quest. You will need to know how to write a javascript function. You will be prompted with a set of quiz on javascript functions. If you demonstrate to have proper skills, then you'll fight a final Boss by writing your own function!", "rules": "You will be battling a Infrastructure Ninja. You will have as much time as you need to prep before the battle, but once the battle starts you will have only seconds per move (keep an eye on the timer in the bottom right; don't run out of time!).", "prep_materials": [{"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function", "title": "Click on this box and read the material on Javascript functions (be sure to have read also the related links). When you think you understood how to create a javascript function, then start the quest! "}], "est_read_time_mins": "20", "seconds_per_question": 30}	{"enemy": {"id": 1, "art": "http://localhost:8000/dynamic/kudos/1/infrastructure_ninja", "level": "1", "title": "Infrastructure Ninja"}}	42	[{"question": "Which one of this pieces of code is the right one to create a javascript function named \\"helloFriend\\" ?", "responses": [{"answer": "fun helloWorld(){}", "correct": false, "language": "text"}, {"answer": "function helloMan{}", "correct": false, "language": "text"}, {"answer": "function helloFriend(){}", "correct": true, "language": "text"}, {"answer": "fun helloFriend(){}", "correct": false, "language": "text"}], "question_type": "quiz_question", "seconds_to_respond": 30}, {"question": "Which one of this pieces of code is the right one to create a javascript function that returns \\"hi buddy!\\" ?", "responses": [{"answer": "fun helloWorld(){ return \\"hi buddy!\\"; }", "correct": false, "language": "text"}, {"answer": "fun helloWorld(){ return(\\"hi buddy\\"); }", "correct": false, "language": "text"}, {"answer": "function helloWorld { return 'hi buddy!'; }", "correct": false, "language": "text"}, {"answer": "function helloWorld(){ return 'hi buddy!'; }", "correct": true, "language": "text"}], "question_type": "quiz_question", "seconds_to_respond": 30}, {"question": "Which one of this pieces of code is the right one to create a javascript function that accepts a parameter (named param) and returns \\"hi \\" plus the content of 'param' ?", "responses": [{"answer": "function helloWorld param { return \\"hi \\" + param ; }", "correct": false, "language": "text"}, {"answer": "function helloWorld(param) { return `hi ${param}!`; }", "correct": true, "language": "text"}, {"answer": "function helloWorld(param) { return 'hi '.param; }", "correct": false, "language": "text"}, {"answer": "fun helloWorld(param){ return \\"hi \\" + param ; }", "correct": false, "language": "text"}], "question_type": "quiz_question", "seconds_to_respond": 30}, {"question": "Write a javascript function named helloWorld that accepts two parameters (named firstName and secondName) and returns 'hello: ' plus the content of FirstName and second name separated by a space. For instance: 'hello: Super Mario'", "responses": [{"answer": "function helloWorld(firstName, secondName) {\\r\\n   return `hello: ${firstName} ${secondName}`;\\r\\n}", "correct": true, "language": "boss_fight_language_javascript"}], "question_type": "boss_fight_question", "seconds_to_respond": 60}]	0	f	Beginner	Code Battle	32	1	back20	{"tags": ["Beginner", "Code Battle", "new"], "creator": {"url": "http://localhost:8000/test4", "handle": "test4"}, "feedbacks": {"ratio": 0, "stats": {"0": 0, "1": 0, "-1": 0}, "feedback": []}, "success_pct": 0, "attempts_count": 1}		\N	\N

@thelostone-mc thelostone-mc requested a review from owocki February 25, 2020 08:32
@cervoneluca
Copy link
Author

hi @owocki ! Any news about this? Let me know if it can work or if it needs modifies, so I can schedule some time to work on it! Sorry to bother you! Thanks!

@owocki
Copy link
Contributor

owocki commented Mar 5, 2020

sorry i've been on parenteal leave so some things dropped.

mind attaching a quick video of the gameplay so that people can see what its like?

do traditional quests still work on this branch?

@cervoneluca
Copy link
Author

Hi Kevin! Yes, traditional quests still works.

I'll make a video very soon and then I'll be back here.

@cervoneluca
Copy link
Author

Hey Kevin. I have an issue with docker. I tried to fetch the upstream repo, and then I checkout my "battle-code-quest" repo and tryied to build the docker composer.

However, now it doesn't build anymore, and it gives me me this error:

Collecting pyshorteners
  Downloading pyshorteners-1.0.0.tar.gz (9.8 kB)
    ERROR: Command errored out with exit status 1:
     command: /usr/bin/python3 -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-5o2gds2v/pyshorteners/setup.py'"'"'; __file__='"'"'/tmp/pip-install-5o2gds2v/pyshorteners/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-install-5o2gds2v/pyshorteners/pip-egg-info
         cwd: /tmp/pip-install-5o2gds2v/pyshorteners/
    Complete output (7 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-5o2gds2v/pyshorteners/setup.py", line 8, in <module>
        README = r.read()
      File "/usr/lib/python3.6/encodings/ascii.py", line 26, in decode
        return codecs.ascii_decode(input, self.errors)[0]
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 21: ordinal not in range(128)
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
ERROR: Service 'web' failed to build: The command '/bin/sh -c pip3 install --upgrade -r test.txt' returned a non-zero code: 1

Have you made changes in the docker-container recently?

@cervoneluca
Copy link
Author

I think that it is related to the URL shortening, I opened an issue for that #6160

@owocki
Copy link
Contributor

owocki commented Mar 6, 2020

this is fixed in ebdb220

@cervoneluca
Copy link
Author

Hi Kevin! Here you have animated gif of the new quest Mechanic.
Of course there is space for a lot of improvements, but I can do them gradually.

Quest Creation (too big to put it here)
https://www.dropbox.com/s/dkj18cq83ouc9x3/quest_creation.gif?dl=0

Quests Database
quest_db

Quest Play
quest_play

@owocki
Copy link
Contributor

owocki commented Mar 9, 2020

pulling out the relevant frame => https://bits.owocki.com/eDuxyBWx

this loops super cool. i guess the answer is computed and marked correct locally in the users javascript enviornment? we just need to be careful about XSS here

@cervoneluca
Copy link
Author

cervoneluca commented Mar 9, 2020

Hi Kevin!
Nope right now it works in a very naive way. Spaces and \n and \t are stripped out from users' input and the obtained string is compared with the one inserted by the quest's creator (trimmed too).

So, everything is made in this two lines of code (in quests/quest_types/code_battle_style.py, lines 68 and 69)

correct_answers = [ele['answer'] for ele in this_question['responses'] if ele['correct']] if this_question['question_type'] != 'boss_fight_question' else [re.sub(r"[\n\t\s]*", "", ele['answer']) for ele in this_question['responses'] if ele['correct']]
their_answers = [unescape(ele) for ele in payload.get('answers')] if this_question['question_type'] != 'boss_fight_question' else [re.sub(r"[\n\t\s]*", "", unescape(ele)) for ele in payload.get('answers')]

and the check is made in line 75

did_they_do_correct = set(correct_answers) == set(their_answers) or (this_question.get('any_correct', False) and len(their_answers))

Now, as I said, this is very very naive and there is room for a lot of improvements.

But, I was waiting for your feedback and suggestions on how to make it less naive, without creating security risks.

I was thinking to evaluate the javascript (or solidity) code of users on server-side and to compare the results with the evaluation of code from quests' creator. But, I'm not super-skilled in python so, do you think that this is possible?

@owocki
Copy link
Contributor

owocki commented Mar 9, 2020

thanks; yeah i think that architecting this in such a way thats not naive but also doesnt have a bunch of security holes / surface area for injection attacks will be a challenge. it def needs to work if variable names are diffrent for xample

@cervoneluca
Copy link
Author

Thank you Kevin!
I think that, in any case, we have to do a little bit of user testing.

So, what do you think is the best way to procede?
In my opinion we can do the following:

  1. I do the code that checks for input and output. It will disregard of variable names and, for now, it will work only for javascript
  2. if it is possible, we do tests with a limited set of users and we'll see what happens.

What do you think?

@cervoneluca
Copy link
Author

Hi @owocki and @octavioamu

I have finished the creation and edit pages and business logic for the new quests game mechanic.

Checkout the animated GIF below.
I wanted to show you also tooltips on mouseover (for questions of type boss-fight) but perhaps I stopped on tooltips longer than needed, so be patient 😅.

Anyway, I found two collateral bugs while creating this (though they didn't blocked me to code). Let me know if you want that I open two issues for them:

  1. After having added the fix from Kevin for filling-up the kudos table, I was able to retrive kudos. However, the autocompleter in the quest always tries to retrieve Kudos that are in the mainnet, so the autocompleter doesn't work (I used a fixed value in the hidden input for kudos as a workaround)
  2. It seems that, after having created quests, they are not shown in "my quests" tab (in the "explore quests" section). Also I'm not able to see the "edit quest" link under mine quests I have created. I thought that it could be an issue related to running gitcoin on localhost, but I don't know exactly what happens.

Anyway, let me know what you thing about this way to handle the new quest mechanics. I need a couple of hours to develop the part related to playing the quest, and another couple of hours to make some code refactoring, and then it should be done.

Below the videos (sorry, I know that animated GIFs are boring because you are not able to fast-forward or fast-backward, but my laptop is to slow to record videos while docker is running).

Have a nice week-end guys.
Stay safe!

Ciao!

  • Quest Creation

quest_creation

  • Quest Editing

quest_edit

@cervoneluca
Copy link
Author

Hi @owocki and @octavioamu

I have developed the business logic for playing the new quest mechanic.
Check out the video attached.

Notes:

  1. currently quests creators can create only quests that return strings or numbers
  2. the mechanic is still a little bit naive. I thing there are ways to win quests by inserting functions much more simpler than ones requested by quest creators
  3. at the end of the quest, players do not win even if they insert the right code. I thing that it is an issue related to running gitcoin in localhost in dev mode (check the following image, you can see that actually the server replies wit a "win" but there are issues with the sender_profile_id.

Schermata 2020-04-05 alle 17 47 32

All the above things can be improved, but it would take time, we can talk on how to improve it.
Let me know what you thing!

Have a nice evening!
Ciao

quest_play

@owocki
Copy link
Contributor

owocki commented Apr 6, 2020

seems pretty promising :) thanks for the comprehensive write up!

ill add this to the @gitcoinco/engineers PR review board, but maybe they'd prefer i do the review since i wrote quests?

also did you regression test the old quests to make sure nothing has broken?

@cervoneluca
Copy link
Author

seems pretty promising :) thanks for the comprehensive write up!

ill add this to the @gitcoinco/engineers PR review board, but maybe they'd prefer i do the review since i wrote quests?

also did you regression test the old quests to make sure nothing has broken?

Hi Kevin! Yes, I did some test on the old quests and nothing seems to be broken. Let me know if you find bugs or dangerous things in the code while reviewing it. I'll fix them quickly!

@cervoneluca
Copy link
Author

hi @owocki , just a ping on this!

@owocki
Copy link
Contributor

owocki commented Apr 15, 2020

sorry for the raido silence. @cervoneluca can you give me a dump of your quests table in your DB so i can ingest it and test? im having a hard time creating my own on your PR for some reason..

@cervoneluca
Copy link
Author

Hi @owocki, first thing first, I fixed a minor issue, so perhaps you want to pull the code again.

I'm not sure if you need the whole dump or just the quest's one, so I'll attach both of them

quests

https://www.dropbox.com/s/0zoisc7oz5nkla7/quests-16042020.dump?dl=0

whole gitcoin

https://www.dropbox.com/s/y5l1caq1wuk4ldy/gitcoin-16042020.dump?dl=0

@cervoneluca
Copy link
Author

hi guys. Any chance this will be published soon or later? 😊

@owocki
Copy link
Contributor

owocki commented May 11, 2020

testing now

@owocki
Copy link
Contributor

owocki commented May 11, 2020

for the quest/new page, i found the ux to e a bit confusing. the system should probalby proimpt the user to let them know what exactly they're supposed to do with both code inputs (bot the sample function and the test function) right? also should there be a title that promps them with what they're supposed to do? ( https://bits.owocki.com/p9u7ey9v )

whats the point of having two quiz types, a code battle + regular quiz, if were just going to allow the user to select on a per question basis the question type in the former?

any chance you've got a couple test quetss that you8've created that you8 can do a psql dump for me on ?

i cant seem to load the file you gave me, what am i doing wrong?

root@9721a2123138:/code/app# ./manage.py loaddata ../quests-16042020.dump
/usr/local/lib/python3.6/dist-packages/sorl/thumbnail/conf/__init__.py:16: RemovedInDjango30Warning: The DEFAULT_CONTENT_TYPE setting is deprecated.
  setattr(self, attr, getattr(obj, attr))
System check identified some issues:

WARNINGS:
?: (debug_toolbar.W001) debug_toolbar.middleware.DebugToolbarMiddleware is missing from MIDDLEWARE.
    HINT: Add debug_toolbar.middleware.DebugToolbarMiddleware to MIDDLEWARE.
CommandError: Problem installing fixture '../quests-16042020': dump is not a known serialization format.

@cervoneluca
Copy link
Author

Hi Kevin!
below the answers to your questions:

for the quest/new page, i found the ux to e a bit confusing. the system should probalby proimpt the user to let them know what exactly they're supposed to do with both code inputs (bot the sample function and the test function) right? also should there be a title that promps them with what they're supposed to do? ( https://bits.owocki.com/p9u7ey9v )

First thing first, the idea to allow quests creator to write down a test function was intended to make the system more engaging for quests creators too.
Quests creators should understand what they are intended to do by reading the tooltips linked to the fields of the form for the quest creation.
I thing that it is possible to add subtitles to explain better to users what they have to do, but IMHO something like: "read carefully the tooltips" written somewhere should be enough.

whats the point of having two quiz types, a code battle + regular quiz, if were just going to allow the user to select on a per question basis the question type in the former?

You're right, it is possibile to add a "boss fight question" to quiz-style quests and so, it is possible to avoid a whole new quests type.

However, the original idea here, was to create a new type of quest in a modular way, so the chances that it breaks the "quiz-style" quests are minimal. I think that when the new quest type is well-tested, then we can work on "merging" the quiz-style and the code-battle style.

any chance you've got a couple test quetss that you8've created that you8 can do a psql dump for me on ?

In this comment there are the links to two dumps, one for the whole DB and one for the quests table. I don't know why you are receiving that error when trying to inject data on your DB instance (I'm not very-expert of django, indeed). However, I saw that in this file, there are these lines at the very start:

/usr/local/lib/python3.6/dist-packages/sorl/thumbnail/conf/__init__.py:16: RemovedInDjango30Warning: The DEFAULT_CONTENT_TYPE setting is deprecated.
  setattr(self, attr, getattr(obj, attr))

Maybe, you should be able to import the data after having deleted those lines.

Let me know!
Thank you!

@@ -136,36 +136,40 @@ var orb_state = function(state) {

$(document).ready(function() {

$('body').keyup(function(e) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of these are indentation cahnges except the if statement?

</div>
`;
const boss_fight_answer_template = `
<hr>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mighte be worth moving these to JSX for basic sanity reasons :)

from ratelimit.decorators import ratelimit

html_escape_table = {
"&": "&amp;",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm this file seems like its copied/pasted no? maybe worth DRYing it up

{% block 'content' %}
<script type='text/javascript' src='//www.midijs.net/lib/midi.js'></script>
<link rel="stylesheet" href="{% static 'v2/css/jquery-ui.css' %}" />
<link href="https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap" rel="stylesheet">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this also seems like it could be DRY'd up

@owocki
Copy link
Contributor

owocki commented May 12, 2020

@gitcoinco/engineers do u all want me to just handle code review on this one, since quests was my YOLO-baby?

@owocki
Copy link
Contributor

owocki commented May 12, 2020

i wonder to what extent we should be worried about JS injection attackson this. from one angle, it would seem to me that JS injection is the whole point of this... but on the other hand, id hate if peoples metamask got hacked or something (and i can see an attacker maybe submitting a quest with nefarious JS in it, expecting us to test it / approv eit)

@cervoneluca
Copy link
Author

@owocki, do I have to do something on my side ? (in the meanwhile that you and the engineers review the code)

@owocki
Copy link
Contributor

owocki commented May 13, 2020

i left some inline comments on the code. some of the more egregious copy/paste should be cleaned up if this is gonna get into prod.

also concerned about the security issues of JS injection.

i also think the UX of new quest is confusing, so can work with u on how to make it more obvious

@danlipert
Copy link
Contributor

closing this unless someone wants to pick it back up

@danlipert danlipert closed this Jul 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants