codeforlife-portal 6.46.1__py2.py3-none-any.whl → 7.1.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of codeforlife-portal might be problematic. Click here for more details.
- cfl_common/common/csp_config.py +0 -2
- cfl_common/common/mail.py +31 -6
- cfl_common/common/migrations/0005_add_worksheets.py +1 -5
- cfl_common/common/migrations/0007_add_pdf_names_to_first_two_worksheets.py +1 -5
- cfl_common/common/migrations/0054_delete_aimmo_models.py +20 -0
- cfl_common/common/models.py +0 -25
- {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/METADATA +3 -4
- {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/RECORD +44 -68
- example_project/portal_test_settings.py +0 -1
- example_project/settings.py +0 -1
- example_project/urls.py +0 -2
- portal/__init__.py +1 -1
- portal/static/portal/sass/partials/_banners.scss +0 -177
- portal/static/portal/sass/partials/_buttons.scss +0 -12
- portal/static/portal/sass/partials/_grids.scss +0 -53
- portal/static/portal/sass/partials/_text.scss +1 -10
- portal/static/portal/sass/styles.scss +0 -1
- portal/strings/play.py +1 -2
- portal/strings/teacher_resources.py +0 -10
- portal/templates/portal/about.html +91 -60
- portal/templates/portal/contribute.html +45 -49
- portal/templates/portal/partials/header.html +0 -12
- portal/templates/portal/play/independent_student_dashboard.html +12 -25
- portal/templates/portal/play/student_dashboard.html +16 -34
- portal/templates/portal/play.html +36 -49
- portal/templates/portal/register.html +1 -1
- portal/templates/portal/teach.html +37 -55
- portal/templates/portal/ten_year_map.html +9 -9
- portal/templatetags/app_tags.py +13 -28
- portal/tests/conftest.py +4 -16
- portal/tests/pageObjects/portal/base_page.py +20 -20
- portal/tests/snapshots/snap_test_partials.py +0 -452
- portal/tests/test_class.py +213 -45
- portal/tests/test_independent_student.py +0 -9
- portal/tests/test_partials.py +6 -56
- portal/tests/test_teacher.py +221 -285
- portal/tests/test_views.py +257 -73
- portal/urls.py +38 -20
- portal/views/cron/user.py +158 -15
- portal/views/student/play.py +36 -25
- portal/views/teacher/teach.py +0 -5
- cfl_common/common/tests/test_migration_aimmo_characters.py +0 -29
- portal/forms/add_game.py +0 -29
- portal/static/portal/img/kurono_hero.jpg +0 -0
- portal/static/portal/img/kurono_landing_hero.png +0 -0
- portal/static/portal/img/kurono_logo.svg +0 -1
- portal/static/portal/img/kurono_logo_grey_background.svg +0 -1
- portal/static/portal/img/kurono_logo_mark.svg +0 -1
- portal/static/portal/img/kurono_resources_hero.jpg +0 -0
- portal/static/portal/img/kurono_story.png +0 -0
- portal/static/portal/img/thumbnail_educate_kurono.png +0 -0
- portal/static/portal/img/thumbnail_kurono_resources.png +0 -0
- portal/static/portal/img/thumbnail_play_kurono.png +0 -0
- portal/static/portal/js/aimmoGame.js +0 -106
- portal/static/portal/sass/partials/_videos.scss +0 -10
- portal/static/portal/video/aimmo_play_now_background_video.mp4 +0 -0
- portal/strings/student_aimmo_dashboard.py +0 -6
- portal/templates/portal/partials/aimmo_games_table.html +0 -89
- portal/templates/portal/play/student_aimmo_dashboard.html +0 -46
- portal/templates/portal/teach/teacher_aimmo_dashboard.html +0 -95
- portal/templatetags/character_list_tags.py +0 -16
- portal/tests/pageObjects/portal/kurono_teacher_dashboard_page.py +0 -49
- portal/tests/test_aimmo_dashboards.py +0 -206
- portal/tests/utils/aimmo_games.py +0 -30
- portal/views/aimmo/__init__.py +0 -0
- portal/views/aimmo/dashboard.py +0 -105
- {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/LICENSE.md +0 -0
- {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/WHEEL +0 -0
- {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/top_level.txt +0 -0
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/* global showPopupConfirmation */
|
|
2
|
-
/* global hidePopupConfirmation */
|
|
3
|
-
|
|
4
|
-
function classesText(classes) {
|
|
5
|
-
return classes
|
|
6
|
-
.map(
|
|
7
|
-
(name, index) =>
|
|
8
|
-
`${
|
|
9
|
-
index === 0
|
|
10
|
-
? ""
|
|
11
|
-
: index === classes.length - 1
|
|
12
|
-
? " and "
|
|
13
|
-
: ", "
|
|
14
|
-
}<strong>${$("<div>").text(name).html()}</strong>`
|
|
15
|
-
)
|
|
16
|
-
.join("");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function clickDeleteGames() {
|
|
20
|
-
let selectedGameIds = [];
|
|
21
|
-
let selectedClasses = [];
|
|
22
|
-
$("input[name='game_ids']:checked").each(function () {
|
|
23
|
-
selectedGameIds.push($(this).val());
|
|
24
|
-
selectedClasses.push($(this).data("className"));
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
if (!selectedGameIds.length) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
let title = "Delete class games";
|
|
32
|
-
let text = `
|
|
33
|
-
<div class='popup-text'>
|
|
34
|
-
<p>Are you sure that you want to delete the game${
|
|
35
|
-
selectedClasses.length > 1 ? "s" : ""
|
|
36
|
-
} for ${classesText(selectedClasses)}?</p>
|
|
37
|
-
<p>This action will delete any progress ${
|
|
38
|
-
selectedClasses.length > 1 ? "those classes have" : "that class has"
|
|
39
|
-
} made.</p>
|
|
40
|
-
</div>`;
|
|
41
|
-
let confirmHandler = "deleteGames()";
|
|
42
|
-
|
|
43
|
-
showPopupConfirmation(title, text, confirmHandler);
|
|
44
|
-
let popup = $(".popup-wrapper");
|
|
45
|
-
popup.data("gameIds", selectedGameIds);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function deleteGames() {
|
|
49
|
-
let gameIds = $("#popup").data("gameIds");
|
|
50
|
-
|
|
51
|
-
$.ajax({
|
|
52
|
-
url: "/kurono/api/games/delete_games/",
|
|
53
|
-
type: "POST",
|
|
54
|
-
data: { game_ids: gameIds },
|
|
55
|
-
traditional: true,
|
|
56
|
-
headers: {
|
|
57
|
-
"X-CSRFToken": $("input[name=csrfmiddlewaretoken]").val(),
|
|
58
|
-
},
|
|
59
|
-
success: function (data) {
|
|
60
|
-
hidePopupConfirmation();
|
|
61
|
-
document.location.reload(true);
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function changeWorksheetConfirmation(gameID, className, worksheetID) {
|
|
67
|
-
let title = "Change Challenge";
|
|
68
|
-
let text =
|
|
69
|
-
"<div class='popup-text'><p>Please confirm that you would like to change the challenge for class: " +
|
|
70
|
-
"<strong class='popup__class-name'></strong>. This will change the level for the students when they rejoin " +
|
|
71
|
-
"the game.</p></div>";
|
|
72
|
-
let confirmHandler = "changeWorksheet()";
|
|
73
|
-
|
|
74
|
-
showPopupConfirmation(title, text, confirmHandler);
|
|
75
|
-
let popup = $(".popup-wrapper");
|
|
76
|
-
popup.data("gameId", gameID);
|
|
77
|
-
popup.data("worksheetId", worksheetID);
|
|
78
|
-
$(".popup__class-name").text(className);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function changeWorksheet() {
|
|
82
|
-
let gameID = $("#popup").data("gameId");
|
|
83
|
-
let worksheetID = $("#popup").data("worksheetId");
|
|
84
|
-
|
|
85
|
-
$.ajax({
|
|
86
|
-
url: "/kurono/api/games/" + gameID + "/",
|
|
87
|
-
type: "PUT",
|
|
88
|
-
data: { worksheet_id: worksheetID },
|
|
89
|
-
success: function (data) {
|
|
90
|
-
hidePopupConfirmation();
|
|
91
|
-
document.location.reload(true);
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
$(document).ready(function () {
|
|
97
|
-
// Handlers for the games checklist and select all checklist
|
|
98
|
-
$('[id^="game_"]').on("click", () => {
|
|
99
|
-
$("#gamesListToggle").prop("checked",
|
|
100
|
-
$('[id^="game_"]:checked').length === $('[id^="game_"]').length);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
$("#gamesListToggle").on("click", () => {
|
|
104
|
-
$('[id^="game_"]').prop("checked", $("#gamesListToggle").is(":checked"));
|
|
105
|
-
});
|
|
106
|
-
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
@import 'base';
|
|
2
|
-
|
|
3
|
-
.video--aimmo--play-online {
|
|
4
|
-
margin-top: 4 * $spacing;
|
|
5
|
-
padding-left: 0px;
|
|
6
|
-
padding-right: 0px;
|
|
7
|
-
-webkit-box-shadow: 0px 4px 18px 0px $color-ui-widget-overlay;
|
|
8
|
-
-moz-box-shadow: 0px 4px 18px 0px $color-ui-widget-overlay;
|
|
9
|
-
box-shadow: 0px 4px 18px 0px $color-ui-widget-overlay;
|
|
10
|
-
}
|
|
Binary file
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
{% load static %}
|
|
2
|
-
{% load app_tags %}
|
|
3
|
-
{% block scripts %}
|
|
4
|
-
<script type="text/javascript" src="{% static 'portal/js/aimmoGame.js' %}"></script>
|
|
5
|
-
{% endblock scripts %}
|
|
6
|
-
|
|
7
|
-
{% if open_play_games %}
|
|
8
|
-
{% include "portal/partials/popup.html" %}
|
|
9
|
-
<table id="games-table" class="games-table header-primary data-primary">
|
|
10
|
-
<tr class="games-table__header">
|
|
11
|
-
<th class="cell-left">
|
|
12
|
-
<p>Class</p>
|
|
13
|
-
</th>
|
|
14
|
-
<th class="cell-left col-xs-6">
|
|
15
|
-
<p>Challenge</p>
|
|
16
|
-
</th>
|
|
17
|
-
<th class="cell-center">
|
|
18
|
-
<p>Action</p>
|
|
19
|
-
</th>
|
|
20
|
-
<th class="cell-center">
|
|
21
|
-
<input id="gamesListToggle" name="gamesListToggle" type="checkbox" value="">
|
|
22
|
-
</th>
|
|
23
|
-
</tr>
|
|
24
|
-
{% for game in open_play_games %}
|
|
25
|
-
<tr>
|
|
26
|
-
<td>
|
|
27
|
-
<div class="games-table__cell">
|
|
28
|
-
<p>{{ game.game_class.name }}
|
|
29
|
-
{% if user.userprofile.teacher == game.game_class.teacher %}
|
|
30
|
-
(You)
|
|
31
|
-
{% else %}
|
|
32
|
-
({{ game.game_class.teacher }})
|
|
33
|
-
{% endif %}
|
|
34
|
-
</p>
|
|
35
|
-
</div>
|
|
36
|
-
</td>
|
|
37
|
-
<td>
|
|
38
|
-
<div class="games-table__cell">
|
|
39
|
-
<div class="dropdown">
|
|
40
|
-
<button id="worksheets_dropdown" class="button--secondary button--secondary--dark button--small button--dropdown"
|
|
41
|
-
data-toggle="dropdown" aria-expanded="false" type="button">
|
|
42
|
-
<div class="dropdown__text">{{ game.worksheet.id }} - {{ game.worksheet.name }}</div>
|
|
43
|
-
</button>
|
|
44
|
-
<ul id="worksheets_dropdown_menu" class="dropdown-menu">
|
|
45
|
-
{% for worksheet in complete_worksheets %}
|
|
46
|
-
<li class="dropdown-menu__option">
|
|
47
|
-
{% if worksheet.name == game.worksheet.name %}
|
|
48
|
-
<a class="button button--small disabled">
|
|
49
|
-
<p class="dropdown-menu__option__text">{{ worksheet.id }} - {{ worksheet.name }}</p>
|
|
50
|
-
<span class="material-icons-outlined">check</span>
|
|
51
|
-
</a>
|
|
52
|
-
{% else %}
|
|
53
|
-
<a class="button button--small" id="worksheet_{{ worksheet.id }}"
|
|
54
|
-
onclick="changeWorksheetConfirmation('{{ game.id|escapejs }}',
|
|
55
|
-
'{{ game.game_class.name|escapejs }}',
|
|
56
|
-
'{{ worksheet.id|escapejs }}')">
|
|
57
|
-
<p class="dropdown-menu__option__text">{{ worksheet.id }} - {{ worksheet.name }}</p>
|
|
58
|
-
</a>
|
|
59
|
-
{% endif %}
|
|
60
|
-
</li>
|
|
61
|
-
{% endfor %}
|
|
62
|
-
{% for worksheet in incomplete_worksheets %}
|
|
63
|
-
<li class="dropdown-menu__option">
|
|
64
|
-
<a class="button button--small disabled">
|
|
65
|
-
<p class="dropdown-menu__option__text">{{ worksheet.id }} - {{ worksheet.name }}</p>
|
|
66
|
-
</a>
|
|
67
|
-
</li>
|
|
68
|
-
{% endfor %}
|
|
69
|
-
</ul>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
</td>
|
|
73
|
-
<td>
|
|
74
|
-
<div class="games-table__buttons">
|
|
75
|
-
<a class="button button--small button--primary" href="{% url base_url id=game.id %}">Play</a>
|
|
76
|
-
</div>
|
|
77
|
-
</td>
|
|
78
|
-
<td class="cell-center">
|
|
79
|
-
<input type="checkbox" name="game_ids" id="game_{{ game.id }}" value="{{ game.id }}" data-class-name="{{ game.game_class.name }}">
|
|
80
|
-
</td>
|
|
81
|
-
</tr>
|
|
82
|
-
{% endfor %}
|
|
83
|
-
</table>
|
|
84
|
-
<button onclick="clickDeleteGames()" class="button button--primary button--primary--danger button--icon pull-right" id="deleteGamesButton">
|
|
85
|
-
Delete<span class="iconify" data-icon="mdi:delete-outline"></span>
|
|
86
|
-
</button>
|
|
87
|
-
{% else %}
|
|
88
|
-
<p>It doesn't look like you have any games created. To create a game, use the 'Select class' button above.</p>
|
|
89
|
-
{% endif %}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
{% extends 'portal/base.html' %}
|
|
2
|
-
{% load static %}
|
|
3
|
-
{% load app_tags banner_tags hero_card_tags card_list_tags character_list_tags %}
|
|
4
|
-
|
|
5
|
-
{% block subNav %}
|
|
6
|
-
<section class="banner banner--aimmo">
|
|
7
|
-
<img title="Kurono logo" alt="Kurono logo" src="{% static 'portal/img/kurono_logo.svg' %}">
|
|
8
|
-
</section>
|
|
9
|
-
{% endblock subNav %}
|
|
10
|
-
|
|
11
|
-
{% block content %}
|
|
12
|
-
{% if not user|is_independent_student %}
|
|
13
|
-
{% if HERO_CARD %}
|
|
14
|
-
<div class="background container">
|
|
15
|
-
{% hero_card hero_card_name="HERO_CARD" %}
|
|
16
|
-
</div>
|
|
17
|
-
|
|
18
|
-
<div class="container carousel-cards-container">
|
|
19
|
-
{% card_list %}
|
|
20
|
-
</div>
|
|
21
|
-
{% else %}
|
|
22
|
-
<div class="background text-center container">
|
|
23
|
-
<h4>My Games</h4>
|
|
24
|
-
<p>
|
|
25
|
-
Oh no! It doesn't look like you have access to any games, yet. You'll need to ask your teacher to set
|
|
26
|
-
some up.
|
|
27
|
-
</p>
|
|
28
|
-
</div>
|
|
29
|
-
{% endif %}
|
|
30
|
-
|
|
31
|
-
<div class="background background--primary">
|
|
32
|
-
<div class="container">
|
|
33
|
-
{% character_list %}
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
{% else %}
|
|
37
|
-
<div class="background text-center container">
|
|
38
|
-
<h4>My Games</h4>
|
|
39
|
-
<p>
|
|
40
|
-
Hi there! 👋 We are sorry, but Kurono is designed to be used in a classroom, and therefore it is not
|
|
41
|
-
available to independent students at this time.
|
|
42
|
-
</p>
|
|
43
|
-
</div>
|
|
44
|
-
{% endif %}
|
|
45
|
-
|
|
46
|
-
{% endblock content %}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
{% extends 'portal/base.html' %}
|
|
2
|
-
{% load static %}
|
|
3
|
-
{% load app_tags %}
|
|
4
|
-
|
|
5
|
-
{% block scripts %}
|
|
6
|
-
{{block.super}}
|
|
7
|
-
<script type="text/javascript" src="{% static 'portal/js/join_create_game_toggle.js' %}"></script>
|
|
8
|
-
{% endblock scripts %}
|
|
9
|
-
|
|
10
|
-
{% block subNav %}
|
|
11
|
-
<section class="banner banner--aimmo">
|
|
12
|
-
<img title="Kurono logo" alt="Kurono logo" src="{% static 'portal/img/kurono_logo.svg' %}">
|
|
13
|
-
</section>
|
|
14
|
-
<div class="sub-nav sub-nav--teacher">
|
|
15
|
-
<div class="container">
|
|
16
|
-
<div class="sub-nav__content">
|
|
17
|
-
<p>Select a class from the dropdown menu to add a new game below</p>
|
|
18
|
-
<div class="dropdown">
|
|
19
|
-
<form autocomplete="off" id="create-game-form" method="post" class="hidden">
|
|
20
|
-
{% csrf_token %}
|
|
21
|
-
<input type="hidden" name="game_class" id="id_game_class">
|
|
22
|
-
</form>
|
|
23
|
-
<button class="button--dropdown" data-toggle="dropdown" aria-expanded="false" id="add_class_dropdown">
|
|
24
|
-
Select class
|
|
25
|
-
</button>
|
|
26
|
-
<ul id="add-class-dropdown-menu" class="dropdown-menu">
|
|
27
|
-
{% for game_class in form.game_class.field.queryset %}
|
|
28
|
-
<li class="dropdown-menu__option">
|
|
29
|
-
{% if game_class.active_game %}
|
|
30
|
-
<a class="button button--regular disabled" data-class-id="{{ game_class.id }}">
|
|
31
|
-
{% else %}
|
|
32
|
-
<a class="button button--regular" id="class_{{ game_class.id }}"
|
|
33
|
-
data-class-id="{{ game_class.id }}"
|
|
34
|
-
onclick='send_event("Kurono", "Clicked", "Create game button");'>
|
|
35
|
-
{% endif %}
|
|
36
|
-
<p class="dropdown-menu__option__text">{{ game_class.name }} {% if user.userprofile.teacher == game_class.teacher %}(You) {% else %}({{ game_class.teacher }}) {% endif %}</p>
|
|
37
|
-
</a>
|
|
38
|
-
</li>
|
|
39
|
-
{% endfor %}
|
|
40
|
-
</ul>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
{% endblock subNav %}
|
|
46
|
-
|
|
47
|
-
{% block content %}
|
|
48
|
-
<div class="background container">
|
|
49
|
-
<section><h4>My games</h4></section>
|
|
50
|
-
{% games_table 'kurono/play' %}
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
<div id="kurono_teacher_dashboard_page"></div>
|
|
54
|
-
<div class="background background--primary">
|
|
55
|
-
<div class="container">
|
|
56
|
-
<div class="row d-flex">
|
|
57
|
-
<div class="col-sm-6 d-flex flex-column">
|
|
58
|
-
<div class="flex-grow-1">
|
|
59
|
-
<h5 class="mt-0">Kurono Resources</h5>
|
|
60
|
-
<p>We have a set of individual and collaborative worksheets that keep the students engaged and having fun whilst
|
|
61
|
-
embedding important Python skills, supported by lesson guides and resource sheets.</p>
|
|
62
|
-
<p>Please visit our dedicated Code for Life Space to find everything you need from lesson plans to solutions.</p>
|
|
63
|
-
<p>This space is only available to teachers.</p>
|
|
64
|
-
</div>
|
|
65
|
-
<div>
|
|
66
|
-
<a href="https://code-for-life.gitbook.io/teaching-resources/v/kurono-teaching-resources/"
|
|
67
|
-
class="button button--primary button--icon col-sm-6" target="_blank">
|
|
68
|
-
Open Kurono resources<span class="iconify" data-icon="mdi:open-in-new"></span>
|
|
69
|
-
</a>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
<div class="col-sm-6">
|
|
73
|
-
<img alt="Kurono Resources" title="Kurono Resources" src="{% static 'portal/img/thumbnail_kurono_resources.png' %}">
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
<div>
|
|
79
|
-
<div class="background container">
|
|
80
|
-
<h5>Tell us what you think of Kurono...</h5>
|
|
81
|
-
<p>Your testing and feedback will help Code for Life deliver an enjoyable game, and will allow us to consult
|
|
82
|
-
with you on resources that will be relevant to teaching computing classes in secondary schools
|
|
83
|
-
(13 — 18 year olds).</p>
|
|
84
|
-
<div class="row background">
|
|
85
|
-
<div class="col-sm-6">
|
|
86
|
-
<a href="https://docs.google.com/forms/d/e/1FAIpQLSdNGbf-oLanNhIqCQ-Yz7mbiTBBjX-8rpdXQUB8XIgBvwwuJg/viewform?usp=sf_link"
|
|
87
|
-
class="button button--primary button--icon col-sm-6" target="_blank">
|
|
88
|
-
Give feedback<span class="iconify" data-icon="mdi:open-in-new"></span>
|
|
89
|
-
</a>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
|
|
95
|
-
{% endblock content %}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from django import template
|
|
2
|
-
from common.models import AimmoCharacter
|
|
3
|
-
|
|
4
|
-
register = template.Library()
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@register.inclusion_tag("portal/partials/character_list.html")
|
|
8
|
-
def character_list():
|
|
9
|
-
"""
|
|
10
|
-
Registers the inclusion tag for the character card list partial.
|
|
11
|
-
The template currently expects a list of elements which each contain the following:
|
|
12
|
-
- name: the heading of the card
|
|
13
|
-
- image_path: the path to the card's image
|
|
14
|
-
- description: the text paragraph of the card
|
|
15
|
-
"""
|
|
16
|
-
return {"characters": AimmoCharacter.objects.sorted()}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
from __future__ import absolute_import
|
|
2
|
-
|
|
3
|
-
from selenium.webdriver.common.by import By
|
|
4
|
-
|
|
5
|
-
from .base_page import BasePage
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class KuronoTeacherDashboardPage(BasePage):
|
|
9
|
-
def __init__(self, browser):
|
|
10
|
-
super(KuronoTeacherDashboardPage, self).__init__(browser)
|
|
11
|
-
|
|
12
|
-
assert self.on_correct_page("kurono_teacher_dashboard_page")
|
|
13
|
-
|
|
14
|
-
def create_game(self, class_id):
|
|
15
|
-
self._click_add_game_dropdown()
|
|
16
|
-
|
|
17
|
-
self.browser.find_element(By.ID, f"class_{class_id}").click()
|
|
18
|
-
|
|
19
|
-
return self
|
|
20
|
-
|
|
21
|
-
def change_game_worksheet(self, worksheet_id):
|
|
22
|
-
self._click_change_worksheet_dropdown()
|
|
23
|
-
|
|
24
|
-
self.browser.find_element(By.ID, f"worksheet_{worksheet_id}").click()
|
|
25
|
-
|
|
26
|
-
self.confirm_dialog()
|
|
27
|
-
|
|
28
|
-
return self
|
|
29
|
-
|
|
30
|
-
def delete_games(self, game_ids):
|
|
31
|
-
# Tick checkboxes
|
|
32
|
-
for game_id in game_ids:
|
|
33
|
-
self.browser.find_element(By.XPATH, f"//input[@name='game_ids' and @value='{game_id}']").click()
|
|
34
|
-
|
|
35
|
-
# Click delete
|
|
36
|
-
self.browser.find_element(By.ID, "deleteGamesButton").click()
|
|
37
|
-
|
|
38
|
-
self.confirm_dialog()
|
|
39
|
-
|
|
40
|
-
return self
|
|
41
|
-
|
|
42
|
-
def _click_change_worksheet_confirm_button(self):
|
|
43
|
-
self.browser.find_element(By.ID, "confirm_button").click()
|
|
44
|
-
|
|
45
|
-
def _click_add_game_dropdown(self):
|
|
46
|
-
self.browser.find_element(By.ID, "add_class_dropdown").click()
|
|
47
|
-
|
|
48
|
-
def _click_change_worksheet_dropdown(self):
|
|
49
|
-
self.browser.find_element(By.ID, "worksheets_dropdown").click()
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
|
|
3
|
-
import pytest
|
|
4
|
-
from aimmo.models import Game
|
|
5
|
-
from aimmo.worksheets import WORKSHEETS
|
|
6
|
-
from common.models import Class, Teacher
|
|
7
|
-
from common.tests.utils.classes import create_class_directly
|
|
8
|
-
from common.tests.utils.organisation import create_organisation_directly, join_teacher_to_organisation
|
|
9
|
-
from common.tests.utils.student import create_school_student_directly
|
|
10
|
-
from common.tests.utils.teacher import signup_teacher_directly
|
|
11
|
-
from django.test.client import Client
|
|
12
|
-
from django.urls.base import reverse
|
|
13
|
-
|
|
14
|
-
from .base_test import BaseTest
|
|
15
|
-
from .conftest import IndependentStudent, SchoolStudent
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
# @pytest.mark.django_db
|
|
19
|
-
# TODO: move tests to kurono microservice and fix them.
|
|
20
|
-
@pytest.mark.skip(reason="Moved game creator to Django")
|
|
21
|
-
def test_student_cannot_access_teacher_dashboard(student1: SchoolStudent, class1: Class):
|
|
22
|
-
"""
|
|
23
|
-
Given you are logged in as a student,
|
|
24
|
-
When you try to access the teacher dashboard,
|
|
25
|
-
Then you cannot access it and are instead redirected.
|
|
26
|
-
"""
|
|
27
|
-
c = Client()
|
|
28
|
-
url = reverse("student_login", kwargs={"access_code": class1.access_code})
|
|
29
|
-
data = {"username": student1.username, "password": student1.password}
|
|
30
|
-
|
|
31
|
-
c.post(url, data)
|
|
32
|
-
|
|
33
|
-
student_dashboard_url = reverse("student_aimmo_dashboard")
|
|
34
|
-
|
|
35
|
-
response_s = c.get(student_dashboard_url)
|
|
36
|
-
|
|
37
|
-
assert response_s.status_code == 200
|
|
38
|
-
|
|
39
|
-
teacher_dashboard_url = reverse("teacher_aimmo_dashboard")
|
|
40
|
-
|
|
41
|
-
response = c.get(teacher_dashboard_url)
|
|
42
|
-
|
|
43
|
-
assert response.status_code == 302
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
# @pytest.mark.django_db
|
|
47
|
-
# TODO: move tests to kurono microservice and fix them.
|
|
48
|
-
@pytest.mark.skip(reason="Moved game creator to Django")
|
|
49
|
-
def test_indep_student_cannot_access_dashboard(
|
|
50
|
-
independent_student1: IndependentStudent,
|
|
51
|
-
):
|
|
52
|
-
"""
|
|
53
|
-
Given you are logged in as an independent student,
|
|
54
|
-
When you try to access the student dashboard,
|
|
55
|
-
Then you can access it but the context only has the banner.
|
|
56
|
-
"""
|
|
57
|
-
c = Client()
|
|
58
|
-
url = reverse("independent_student_login")
|
|
59
|
-
data = {"username": independent_student1.username, "password": independent_student1.password}
|
|
60
|
-
|
|
61
|
-
c.post(url, data)
|
|
62
|
-
|
|
63
|
-
student_dashboard_url = reverse("student_aimmo_dashboard")
|
|
64
|
-
|
|
65
|
-
response = c.get(student_dashboard_url)
|
|
66
|
-
|
|
67
|
-
assert response.status_code == 200
|
|
68
|
-
assert "BANNER" in response.context
|
|
69
|
-
assert "HERO_CARD" not in response.context
|
|
70
|
-
assert "CARD_LIST" not in response.context
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# @pytest.mark.django_db
|
|
74
|
-
# TODO: move tests to kurono microservice and fix them.
|
|
75
|
-
@pytest.mark.skip(reason="Moved game creator to Django")
|
|
76
|
-
def test_student_aimmo_dashboard_loads(student1: SchoolStudent, class1: Class, aimmo_game1: Game):
|
|
77
|
-
"""
|
|
78
|
-
Given an aimmo game is linked to a class,
|
|
79
|
-
When a student of that class goes on the Student Kurono Dashboard page,
|
|
80
|
-
Then the page loads and the context contains the hero card and card list
|
|
81
|
-
associated to the aimmo game.
|
|
82
|
-
|
|
83
|
-
Then, given that the class no longer has a game linked to it,
|
|
84
|
-
When the student goes on the same page,
|
|
85
|
-
Then the page still loads but the context no longer contains the hero card
|
|
86
|
-
or the card list elements.
|
|
87
|
-
"""
|
|
88
|
-
c = Client()
|
|
89
|
-
student_login_url = reverse("student_login", kwargs={"access_code": class1.access_code})
|
|
90
|
-
data = {"username": student1.username, "password": student1.password}
|
|
91
|
-
|
|
92
|
-
c.post(student_login_url, data)
|
|
93
|
-
|
|
94
|
-
student_dashboard_url = reverse("student_aimmo_dashboard")
|
|
95
|
-
response = c.get(student_dashboard_url)
|
|
96
|
-
|
|
97
|
-
assert response.status_code == 200
|
|
98
|
-
assert "HERO_CARD" in response.context
|
|
99
|
-
assert "CARD_LIST" in response.context
|
|
100
|
-
|
|
101
|
-
aimmo_game1.delete()
|
|
102
|
-
|
|
103
|
-
url = reverse("student_aimmo_dashboard")
|
|
104
|
-
response = c.get(url)
|
|
105
|
-
|
|
106
|
-
assert response.status_code == 200
|
|
107
|
-
assert "HERO_CARD" not in response.context
|
|
108
|
-
assert "CARD_LIST" not in response.context
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
# TODO: move tests to kurono microservice and fix them.
|
|
112
|
-
# Selenium tests
|
|
113
|
-
# class TestAimmoDashboardFrontend(BaseTest):
|
|
114
|
-
# def test_admin_permissions_actions(self):
|
|
115
|
-
# # Create admin teacher, school and class
|
|
116
|
-
# admin_email, admin_password = signup_teacher_directly()
|
|
117
|
-
# school = create_organisation_directly(admin_email)
|
|
118
|
-
# admin_class, _, admin_access_code = create_class_directly(admin_email, "class 1")
|
|
119
|
-
|
|
120
|
-
# # create another teacher and add as not admin, create a class
|
|
121
|
-
# non_admin_email, non_admin_password = signup_teacher_directly()
|
|
122
|
-
# join_teacher_to_organisation(non_admin_email, school.name, school.postcode, is_admin=False)
|
|
123
|
-
# non_admin_class, _, non_admin_access_code = create_class_directly(non_admin_email, "class 2")
|
|
124
|
-
|
|
125
|
-
# non_admin_teacher: Teacher = Teacher.objects.get(new_user__email=non_admin_email)
|
|
126
|
-
# admin_teacher: Teacher = Teacher.objects.get(new_user__email=admin_email)
|
|
127
|
-
|
|
128
|
-
# c = Client()
|
|
129
|
-
# # check if non_admin cannot create a game for the admin
|
|
130
|
-
# c.login(username=non_admin_email, password=non_admin_password)
|
|
131
|
-
# response = c.post(reverse("teacher_aimmo_dashboard"), {"game_class": admin_class.pk})
|
|
132
|
-
# assert response.status_code == 200
|
|
133
|
-
# assert Game.objects.filter(game_class__teacher__school=school).count() == 0
|
|
134
|
-
|
|
135
|
-
# # create a game by non admin and by admin, then check if admin can delete both
|
|
136
|
-
# response = c.post(reverse("teacher_aimmo_dashboard"), {"game_class": non_admin_class.pk})
|
|
137
|
-
# assert response.status_code == 302
|
|
138
|
-
# assert Game.objects.filter(game_class__teacher=non_admin_teacher).count() == 1
|
|
139
|
-
# c.logout()
|
|
140
|
-
|
|
141
|
-
# c.login(username=admin_email, password=admin_password)
|
|
142
|
-
# response = c.post(reverse("teacher_aimmo_dashboard"), {"game_class": admin_class.pk})
|
|
143
|
-
# assert response.status_code == 302
|
|
144
|
-
# assert Game.objects.filter(game_class__teacher__school=school).count() == 2
|
|
145
|
-
|
|
146
|
-
# admin_game = Game.objects.get(game_class=admin_class)
|
|
147
|
-
# non_admin_game = Game.objects.get(game_class=non_admin_class)
|
|
148
|
-
|
|
149
|
-
# # test admin deleting games
|
|
150
|
-
# c.post(reverse("game-delete-games"), {"game_ids": admin_game.id})
|
|
151
|
-
# c.post(reverse("game-delete-games"), {"game_ids": non_admin_game.id})
|
|
152
|
-
# assert Game.objects.filter(game_class__teacher__school=school, is_archived=True).count() == 2
|
|
153
|
-
# # now make check if the non admin can delete game
|
|
154
|
-
# response = c.post(reverse("teacher_aimmo_dashboard"), {"game_class": admin_class.pk})
|
|
155
|
-
# assert response.status_code == 302
|
|
156
|
-
# assert Game.objects.filter(game_class__teacher=admin_teacher, is_archived=False).count() == 1
|
|
157
|
-
# c.logout()
|
|
158
|
-
|
|
159
|
-
# c.login(username=non_admin_email, password=non_admin_password)
|
|
160
|
-
# response = c.post(reverse("game-delete-games"), {"game_ids": admin_game.id})
|
|
161
|
-
# assert response.status_code == 204
|
|
162
|
-
# assert Game.objects.filter(game_class__teacher=admin_teacher, is_archived=False).count() == 1
|
|
163
|
-
|
|
164
|
-
# def test_worksheet_dropdown_changes_worksheet(self):
|
|
165
|
-
# teacher_email, teacher_password = signup_teacher_directly()
|
|
166
|
-
# create_organisation_directly(teacher_email)
|
|
167
|
-
# klass, class_name, access_code = create_class_directly(teacher_email)
|
|
168
|
-
# student_name, student_password, _ = create_school_student_directly(access_code)
|
|
169
|
-
|
|
170
|
-
# worksheet1 = WORKSHEETS.get(1)
|
|
171
|
-
# worksheet2 = WORKSHEETS.get(2)
|
|
172
|
-
|
|
173
|
-
# self.selenium.get(self.live_server_url)
|
|
174
|
-
# page = self.go_to_homepage().go_to_teacher_login_page().login(teacher_email, teacher_password)
|
|
175
|
-
# page = page.go_to_kurono_teacher_dashboard_page().create_game(klass.id)
|
|
176
|
-
|
|
177
|
-
# game = Game.objects.get(game_class=klass)
|
|
178
|
-
|
|
179
|
-
# assert game.worksheet == worksheet1
|
|
180
|
-
|
|
181
|
-
# page.change_game_worksheet(worksheet2.id)
|
|
182
|
-
|
|
183
|
-
# game = Game.objects.get(game_class=klass)
|
|
184
|
-
|
|
185
|
-
# assert game.worksheet == worksheet2
|
|
186
|
-
|
|
187
|
-
# def test_delete_games(self):
|
|
188
|
-
# teacher_email, teacher_password = signup_teacher_directly()
|
|
189
|
-
# create_organisation_directly(teacher_email)
|
|
190
|
-
|
|
191
|
-
# klass1, _, _ = create_class_directly(teacher_email)
|
|
192
|
-
# game1 = Game(game_class=klass1)
|
|
193
|
-
# game1.save()
|
|
194
|
-
|
|
195
|
-
# klass2, _, _ = create_class_directly(teacher_email)
|
|
196
|
-
# game2 = Game(game_class=klass2)
|
|
197
|
-
# game2.save()
|
|
198
|
-
|
|
199
|
-
# assert Game.objects.count() == 2
|
|
200
|
-
|
|
201
|
-
# self.selenium.get(self.live_server_url)
|
|
202
|
-
# page = self.go_to_homepage().go_to_teacher_login_page().login(teacher_email, teacher_password)
|
|
203
|
-
# page.go_to_kurono_teacher_dashboard_page().delete_games([game1.id, game2.id])
|
|
204
|
-
|
|
205
|
-
# assert Game.objects.filter(is_archived=False).count() == 0
|
|
206
|
-
# assert Game.objects.filter(is_archived=True).count() == 2
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
from aimmo.models import Game
|
|
2
|
-
from common.models import Class
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def generate_name():
|
|
6
|
-
name = "Game %d" % generate_name.next_id
|
|
7
|
-
|
|
8
|
-
generate_name.next_id += 1
|
|
9
|
-
|
|
10
|
-
return name
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
generate_name.next_id = 1
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def create_aimmo_game_directly(klass: Class, worksheet_id: int) -> Game:
|
|
17
|
-
"""Generate an aimmo game with the details given.
|
|
18
|
-
|
|
19
|
-
Args:
|
|
20
|
-
klass (Class): The instance of the class.
|
|
21
|
-
worksheet_id (int): The id of the worksheet.
|
|
22
|
-
|
|
23
|
-
Returns:
|
|
24
|
-
game: Game: The game model instance.
|
|
25
|
-
"""
|
|
26
|
-
name = generate_name()
|
|
27
|
-
|
|
28
|
-
game = Game.objects.create(name=name, game_class=klass, worksheet_id=worksheet_id)
|
|
29
|
-
|
|
30
|
-
return game
|
portal/views/aimmo/__init__.py
DELETED
|
File without changes
|