Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
| Download
Views: 39598
1
##############################################################################
2
#
3
# CoCalc: Collaborative Calculation in the Cloud
4
#
5
# Copyright (C) 2016, Sagemath Inc.
6
#
7
# This program is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
#
20
###############################################################################
21
22
# Pure functions used in the course manager
23
24
# CoCalc libraries
25
misc = require('smc-util/misc')
26
{defaults, required} = misc
27
28
immutable = require('immutable')
29
30
exports.STEPS = (peer) ->
31
if peer
32
return ['assignment', 'collect', 'peer_assignment', 'peer_collect', 'return_graded']
33
else
34
return ['assignment', 'collect', 'return_graded']
35
36
exports.previous_step = (step, peer) ->
37
switch step
38
when 'collect'
39
return 'assignment'
40
when 'return_graded'
41
if peer
42
return 'peer_collect'
43
else
44
return 'collect'
45
when 'assignment'
46
return
47
when 'peer_assignment'
48
return 'collect'
49
when 'peer_collect'
50
return 'peer_assignment'
51
else
52
console.warn("BUG! previous_step('#{step}')")
53
54
exports.step_direction = (step) ->
55
switch step
56
when 'assignment'
57
return 'to'
58
when 'collect'
59
return 'from'
60
when 'return_graded'
61
return 'to'
62
when 'peer_assignment'
63
return 'to'
64
when 'peer_collect'
65
return 'from'
66
else
67
console.warn("BUG! step_direction('#{step}')")
68
69
exports.step_verb = (step) ->
70
switch step
71
when 'assignment'
72
return 'assign'
73
when 'collect'
74
return 'collect'
75
when 'return_graded'
76
return 'return'
77
when 'peer_assignment'
78
return 'assign'
79
when 'peer_collect'
80
return 'collect'
81
else
82
console.warn("BUG! step_verb('#{step}')")
83
84
exports.step_ready = (step, n) ->
85
switch step
86
when 'assignment'
87
return ''
88
when 'collect'
89
return if n >1 then ' who have already received it' else ' who has already received it'
90
when 'return_graded'
91
return ' whose work you have graded'
92
when 'peer_assignment'
93
return ' for peer grading'
94
when 'peer_collect'
95
return ' who should have peer graded it'
96
97
# Takes a student immutable.Map with key 'student_id'
98
# Returns a list of students `x` shaped like:
99
# {
100
# first_name : string
101
# last_name : string
102
# last_active : integer
103
# hosting : bool
104
# email_address : string
105
# }
106
exports.parse_students = (student_map, user_map, redux) ->
107
v = exports.immutable_to_list(student_map, 'student_id')
108
for x in v
109
if x.account_id?
110
user = user_map.get(x.account_id)
111
x.first_name ?= user?.get('first_name') ? ''
112
x.last_name ?= user?.get('last_name') ? ''
113
if x.project_id?
114
x.last_active = redux.getStore('projects').get_last_active(x.project_id)?.get(x.account_id)?.getTime?()
115
upgrades = redux.getStore('projects').get_total_project_quotas(x.project_id)
116
if upgrades?
117
x.hosting = upgrades.member_host
118
119
x.first_name ?= ""
120
x.last_name ?= ""
121
x.last_active ?= 0
122
x.hosting ?= false
123
x.email_address ?= ""
124
return v
125
126
# Transforms Iterable<K, M<i, m>> to [M<i + primary_key, m + K>] where primary_key maps to K
127
# Dunno if either of these is readable...
128
# Turns Map(Keys -> Objects{...}) into [Objects{primary_key : Key, ...}]
129
exports.immutable_to_list = (x, primary_key) ->
130
if not x?
131
return
132
v = []
133
x.map (val, key) ->
134
v.push(misc.merge(val.toJS(), {"#{primary_key}":key}))
135
return v
136
137
# Returns a list of matched objects and the number of objects
138
# which were in the original list but omitted in the returned list
139
exports.compute_match_list = (opts) ->
140
opts = defaults opts,
141
list : required # list of objects<M>
142
search_key : required # M.search_key property to match over
143
search : required # matches to M.search_key
144
ignore_case : true
145
{list, search, search_key, ignore_case} = opts
146
if not search # why are you even calling this..
147
return {list:list, num_omitted:0}
148
149
num_omitted = 0
150
words = misc.split(search)
151
matches = (x) =>
152
if ignore_case
153
k = x[search_key].toLowerCase?()
154
else
155
k = x[search_key]
156
for w in words
157
if k.indexOf(w) == -1 # no match
158
num_omitted += 1
159
return false
160
return true
161
list = list.filter matches
162
return {list:list, num_omitted:num_omitted}
163
164
# Returns
165
# `list` partitioned into [not deleted, deleted]
166
# where each partition is sorted based on the given `compare_function`
167
# deleted is not included by default
168
exports.order_list = (opts) ->
169
opts = defaults opts,
170
list : required
171
compare_function : required
172
reverse : false
173
include_deleted : false
174
{list, compare_function, include_deleted} = opts
175
176
x = list.filter (x) => x.deleted
177
sorted_deleted = x.sort compare_function
178
179
y = list.filter (x) => not x.deleted
180
list = y.sort compare_function
181
182
if opts.reverse
183
list.reverse()
184
185
if include_deleted
186
list = list.concat(sorted_deleted)
187
188
return {list:list, deleted:x, num_deleted:sorted_deleted.length}
189
190
sort_on_string_field = (field) ->
191
(a,b) -> misc.cmp(a[field].toLowerCase(), b[field].toLowerCase())
192
193
sort_on_numerical_field = (field) ->
194
(a,b) -> misc.cmp(a[field] * -1, b[field] * -1)
195
196
exports.pick_student_sorter = (sort) ->
197
switch sort.column_name
198
when "email" then sort_on_string_field("email_address")
199
when "first_name" then sort_on_string_field("first_name")
200
when "last_name" then sort_on_string_field("last_name")
201
when "last_active" then sort_on_numerical_field("last_active")
202
when "hosting" then sort_on_numerical_field("hosting")
203
204