Skip to content
This repository has been archived by the owner on Feb 23, 2022. It is now read-only.

Commit

Permalink
Merge branch 'main' into test
Browse files Browse the repository at this point in the history
  • Loading branch information
fpereiro committed Jun 8, 2021
2 parents 23593b5 + 3cb08b6 commit e9969bf
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 5 deletions.
25 changes: 22 additions & 3 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ def programs_page (request):

date = round (date / 24)

programs.append ({'id': item ['id'], 'code': item ['code'], 'date': texts ['ago-1'] + ' ' + str (date) + ' ' + measure + ' ' + texts ['ago-2'], 'level': item ['level'], 'name': item ['name'], 'adventure_name': item.get ('adventure_name')})
programs.append ({'id': item ['id'], 'code': item ['code'], 'date': texts ['ago-1'] + ' ' + str (date) + ' ' + measure + ' ' + texts ['ago-2'], 'level': item ['level'], 'name': item ['name'], 'adventure_name': item.get ('adventure_name'), 'public': item.get ('public')})

return render_template('programs.html', lang=requested_lang(), menu=render_main_menu('programs'), texts=texts, ui=ui, auth=TRANSLATIONS.data [requested_lang ()] ['Auth'], programs=programs, username=username, current_page='programs', from_user=from_user, adventures=adventures)

Expand Down Expand Up @@ -625,9 +625,10 @@ def index(level, step):
result = db_get ('programs', {'id': step})
if not result:
return 'No such program', 404
# Allow only the owner of the program, the admin user and the teacher users to access the program
# If the program is not public, allow only the owner of the program, the admin user and the teacher users to access the program
user = current_user (request)
if user ['username'] != result ['username'] and not is_admin (request) and not is_teacher (request):
public_program = 'public' in result and result ['public']
if not public_program and user ['username'] != result ['username'] and not is_admin (request) and not is_teacher (request):
return 'No such program!', 404
loaded_program = result ['code']
loaded_program_name = result ['name']
Expand Down Expand Up @@ -930,6 +931,24 @@ def save_program (user):

return jsonify({'name': name})

@app.route('/programs/share', methods=['POST'])
@requires_login
def share_unshare_program(user):
body = request.json
if not type_check (body, 'dict'):
return 'body must be an object', 400
if not object_check (body, 'id', 'str'):
return 'id must be a string', 400
if not object_check (body, 'public', 'bool'):
return 'public must be a string', 400

result = db_get ('programs', {'id': body ['id']})
if not result or result ['username'] != user ['username']:
return 'No such program!', 404

db_update ('programs', {'id': body ['id'], 'public': 1 if body ['public'] else None})
return jsonify({})

@app.route('/translate/<source>/<target>')
def translate_fromto(source, target):
# FIXME: right now loading source file on demand. We might need to cache this...
Expand Down
186 changes: 186 additions & 0 deletions coursedata/adventures/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -690,4 +690,190 @@ adventures:
... think of other fun things to add?
start_code: ""

fortune:
name: "Fortune teller"
description: "Let Hedy predict the future"
image: "fortuneteller.png"
default_save_name: "Fortune Teller"
levels:
1:
story_text: |
## Fortune Teller
Have you ever been to a carnival and had your future predicted by a fortune teller? Or have you ever played with a magic eight ball?
Then you probably know that they can't really predict your future, but it's still fun to play!
In the upcoming levels you can learn how to create your own fortune telling machine!
In level 1 you can start off easy by letting Hedy introduce herself as a fortune teller and let her echo the players' answers.
Like this:
## Example Hedy code
```
print Hello, I'm Hedy the fortune teller!
ask Who are you?
print Let me take a look in my crystall ball
print I see... I see...
echo Your name is...
```
## Challenge
Hedy now only tells you your name. Can you expand the code so that Hedy can predict more things about you?
Obviously, Hedy isn't a very good fortune teller yet, as she can only repeat the answers that were given by the players!
Take a look in level 2 to improve your fortune teller.
start_code: ""
2:
story_text: |
## Fortune Teller
In level 1 you've created your first fortune telling machine, but Hedy couldn't really predict anything, only echo.
In level 2 you can use a variable and the `at random` command to really let Hedy choose an answer for you. Check out this code for instance:
## Example Hedy Code
In this example the player can ask Hedy a yes-no question and Hedy will pick a random answer for you.
```
print I’m Hedy the fortune teller!
question is ask What do you want to know?
print This is what you want to know: question
answers is yes, no, maybe
print My crystal ball says... answers at random
```
## Challenges
Now, Hedy can only answer yes, no or maybe. Can you give Hedy more answer options, like 'definitely' or 'ask again'.
start_code: ""

3:
story_text: |
## Fortune Teller
Level 3 has no new functions, but allows you to practice with using the quotation marks.
You can remake your level 2 code, and make sure to add the quotation marks in the right places!
Mind that in level 2, we couldn't use the word 'question' as both the name of the variable and a normal word that could be printed.
The quotation marks in level 3 make this possible!
Important! Mind that now that we're using quotation marks, Hedy will get confused when you use the apostrophe for contractions like I'm or What's.
Make sure to remove those apostophes and change the spelling to Im or Whats.
## Example Hedy Code
```
print 'Im Hedy the fortune teller!'
question is ask What do you want to know?
print 'This is your question: ' question
answers is yes, no, maybe
print 'My crystal ball says...' answers at random
```
start_code: ""
4:
story_text: |
## Fortune Teller
In Level 4 you'll learn to (secretly) tip the odds in your favor, when using the fortune teller!
By using `if` and `else` you can make sure that you will always get a good fotune, while other people might not.
Check out this example to find out how.
## Example Hedy Code
```
print 'Im Hedy the fortune teller!'
print 'I can predict if youll win the lottery tomorrow!'
person is ask Who are you?
if person is Hedy print 'You will definitely win!' else print 'Bad luck! Someone else will win!'
```
Replace Hedy with your own name in the last line, and Hedy will always predict that you will win the lottery and others won't!
Of course this might raise some suspicion with the other players... To avoid that, you can make sure that Hedy does give different answers everytime you run the code.
But of course, still gives you a positive answer and the other players a negative one.
## Example Hedy Code 2
```
print 'Im Hedy the fortune teller!'
print 'I can predict if youll win the lottery tomorrow!'
person is ask Who are you?
goodanswer is Hurray! You win!, You will definitely win!, We have a winner!
badanswer is Bad luck! Try again!, Someone else will win, You lose!
if person is Hedy print goodanswer at random else print badanswer at random
```
## Challenges
This concept can be used to make may different programs, just be creative! For example you could create a machine that predicts that your favorite sports team will beat all the competitors!
Or you could make Snow White's magic mirror on the wall, to tell everyone you are the fairest of them all!
Let your imagination do the work!

start_code: ""
5:
story_text: |
## Fortune Teller
In level 5 you can use the repeat command to make your machine tell multiple fortunes at once.
## Example Hedy Code
```
print 'Im Hedy the fortune teller!'
print 'You can ask 3 questions!'
repeat 3 times question is ask What do you want to know?
answer is yes, no, maybe
repeat 3 times print 'My crystall ball says... ' answer at random
```
## Challenge
As you can see, the questions aren't printed in this example. That's because the variable `question` was changed 3 times.
Everytime the player fills in the new answer, Hedy overwrites the previous one, so the first answer the player gave is forgotten.
This means you can't print all the questions this way.
By using 3 different variables instead of 1 (for example `question1` , `question2` and `question3`), you could solve the problem and print the questions.
This does mean that you can only use `repeat` for the answers, and you will have to ask and print all the questions seperately.
Can you do it?
In level 7 the layout of repeat command will change, which enables you to repeat multiple lines at once.
start_code: ""

6:
story_text: |
## Fortune Teller
In level 6 you can use maths in your predictions as a fortune teller. This allows you to make up (silly) formulas to calculate the future.
For example you could calculate how rich you'll get or how many kids you will have when you grow up.
## Example Hedy Code
```
print 'Im Hedy the fortune teller!'
print 'I can predict how many kids youll get when you grow up!'
age is ask How old are you?
siblings is How many siblings do you have?
length is How tall are you in centimetres?
kids is length / age
kids is kids - siblings
print 'You will get ...'
print kids ' kids!'
```
## Example Silly Fortune Teller
If the previous example wasn't silly enough for you, take a look at this one!
```
print 'Im Hedy the silly fortune teller!'
print 'I will predict how smart you are!'
football is ask On a scale 1-10 how much do you love football?
bananas is ask How many bananas did you eat this week?
hygiene is ask How many times did you wash your hands today?
result is bananas + hygiene
result is result * football
print 'You are ' result ' percent smart.'
```
start_code: ""

7:
story_text: |
## Fortune Teller
In level 5 you've learned how to use repeat to make the fortune teller answer 3 questions in a row, but we had a problem with printing the questions.
In level 7 that problem is solved, because of the new way of using the repeat command.
In the next example you can have your fortune teller ask 3 questions and also print them!
## Example Hedy Code
```
print 'Im Hedy the fortune teller!'
print 'You can ask me 3 questions.'
answers are yes, no, maybe
repeat 3 times
question is ask What do you want to know?
print question
print 'My crystall ball says...' answers at random
```
start_code: ""
5 changes: 5 additions & 0 deletions coursedata/texts/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ Auth:
unsaved_changes: "You have an unsaved program. Do you want to leave without saving it?"
save_success: "Success"
save_success_detail: "Program saved successfully"
share_success_detail: "Program shared successfully"
answer_question: "You can't run the program until you answer the question first"
Programs:
recent: "My recent programs"
Expand All @@ -183,5 +184,9 @@ Programs:
open: "Open"
delete: "Delete"
delete_confirm: "Are you sure you want to delete the program?"
share: "Share"
share_confirm: "Are you sure you want to make the program public?"
unshare: "Unshare"
unshare_confirm: "Are you sure you want to make the program private?"
no_programs: "You have no programs yet."
write_first: "Write your first program!"
2 changes: 2 additions & 0 deletions e2e_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ def suite (username):
['retrieve programs before saving any', 'get', '/programs_list', {}, {}, 200, retrieveProgramsBefore],
['create program', 'post', '/programs', {}, {'code': 'print Hello world', 'name': 'Program 1', 'level': 1}, 200],
['retrieve programs after saving one', 'get', '/programs_list', {}, {}, 200, retrieveProgramsAfter],
['share program', 'post', '/programs/share', {}, lambda state: {'id': state ['program'] ['id'], 'public': True}, 200],
['unshare program', 'post', '/programs/share', {}, lambda state: {'id': state ['program'] ['id'], 'public': False}, 200],
['delete program', 'get', lambda state: '/programs/delete/' + state ['program'] ['id'], {}, {}, 302],
['retrieve programs after deleting saved program', 'get', '/programs_list', {}, {}, 200, retrieveProgramsBefore],
['destroy account', 'post', '/auth/destroy', {}, {}, 200]
Expand Down
21 changes: 21 additions & 0 deletions static/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,27 @@ function feedback(answer) {
}
}

window.share_program = function share_program (id, Public, reload) {
$.ajax({
type: 'POST',
url: '/programs/share',
data: JSON.stringify({
id: id,
public: Public
}),
contentType: 'application/json',
dataType: 'json'
}).done(function(response) {
$ ('#okbox').show ();
$ ('#okbox .caption').html (window.auth.texts.save_success);
$ ('#okbox .details').html (window.auth.texts.share_success_detail);
if (reload) location.reload ();
}).fail(function(err) {
console.error(err);
error.show(ErrorMessages.Connection_error, JSON.stringify(err));
});
}

/**
* Do a POST with the error to the server so we can log it
*/
Expand Down
2 changes: 1 addition & 1 deletion static/js/tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ $(function() {
});

// If the loaded program (directly requested by link with id) matches the currently selected tab, use that, overriding the loaded program that came in the adventure or level.
if (window.State.loaded_program && window.State.adventure_name_onload === tabName) {
if (window.State.loaded_program && (window.State.adventure_name_onload || 'level') === tabName) {
$ ('#program_name').val (window.State.loaded_program_name);
window.editor.setValue (window.State.loaded_program);
}
Expand Down
7 changes: 7 additions & 0 deletions templates/programs.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
<a href="{{localize_link ('/hedy/' + program.level|string + '/' + program.id)}}">{{ texts.open }}</a>

<a href="#" onclick="if (confirm ('{{ texts.delete_confirm }}')) window.open ('/programs/delete/{{program.id}}', '_self')">{{ texts.delete }}</a>
{% if program.public %}
<a href="#" onclick="if (confirm ('{{ texts.unshare_confirm }}')) window.share_program ('{{program.id}}', false, true)">{{ texts.unshare}}</a>
{% else %}
<a href="#" onclick="if (confirm ('{{ texts.share_confirm }}')) window.share_program ('{{program.id}}', true, true)">{{ texts.share}}</a>
{% endif %}
<pre>{{program.code | truncate (50) }}</pre>
</li>
<br>
Expand All @@ -34,5 +39,7 @@
{% endblock %}
{% block scripts %}
<script src="{{static('/vendor/jquery.min.js')}}" type="text/javascript"></script>
<script src="{{static('/js/app.js')}}" type="text/javascript"></script>
<script src="{{static('/js/auth.js')}}" type="text/javascript"></script>
<script>window.State = {lang: "{{ lang }}", level: "{{ level }}"}</script>
{% endblock %}
2 changes: 1 addition & 1 deletion website/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def is_admin (request):

def is_teacher (request):
user = current_user (request)
return bool (user ['is_teacher'])
return bool ('is_teacher' in user and user ['is_teacher'])

# The translations are imported here because current_user above is used by hedyweb.py and we need to avoid circular dependencies
import hedyweb
Expand Down

0 comments on commit e9969bf

Please sign in to comment.