Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
pvk-tool
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
13
Issues
13
List
Boards
Labels
Service Desk
Milestones
Merge Requests
2
Merge Requests
2
Operations
Operations
Incidents
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
amiv
pvk-tool
Commits
da0b678e
Commit
da0b678e
authored
Dec 02, 2017
by
Alexander Dietmüller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Frontend: Api can now create/update/delete items. CourseList and Sidebar use this.
parent
69687bfa
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
222 additions
and
38 deletions
+222
-38
Frontend/src/CourseList.js
Frontend/src/CourseList.js
+27
-5
Frontend/src/UserSidebar.js
Frontend/src/UserSidebar.js
+22
-11
Frontend/src/api.js
Frontend/src/api.js
+173
-22
No files found.
Frontend/src/CourseList.js
View file @
da0b678e
const
m
=
require
(
'
mithril
'
);
const
{
Courses
}
=
require
(
'
./api.js
'
);
const
{
courses
,
userCourses
}
=
require
(
'
./api.js
'
);
function
isSelected
(
course
)
{
return
userCourses
.
selected
.
some
(
sel
=>
sel
===
course
.
_id
);
}
function
isBusy
()
{
return
userCourses
.
resources
.
selections
.
isBusy
()
};
module
.
exports
=
{
oninit
()
{
Courses
.
load
();
},
oninit
()
{
courses
.
get
();
},
view
()
{
return
m
(
'
table
'
,
[
...
...
@@ -15,16 +21,32 @@ module.exports = {
m
(
'
th
'
,
'
Ending time
'
),
]),
]),
m
(
'
tbody
'
,
C
ourses
.
list
.
map
(
course
=>
m
(
'
tbody
'
,
c
ourses
.
list
.
map
(
course
=>
m
(
'
tr
'
,
[
m
(
'
td
'
,
course
.
lecture
.
title
),
m
(
'
td
'
,
course
.
lecture
.
department
),
m
(
'
td
'
,
course
.
assistant
.
name
),
m
(
'
td
'
,
course
.
assistant
),
course
.
datetimes
.
map
(
timeslot
=>
[
m
(
'
td
'
,
timeslot
.
start
),
m
(
'
td
'
,
timeslot
.
end
),
]),
m
(
'
td
'
,
m
(
'
button
'
,
'
add course
'
)),
m
(
'
td
'
,
m
(
'
button
'
,
{
onclick
()
{
userCourses
.
selectCourse
(
course
.
_id
);
},
disabled
:
isSelected
(
course
)
||
isBusy
(),
// ?
// true : false,
// return false;
// return !((UserCourses.selected.courses || []).some(sel =>
// sel === course._id));
// },
},
'
add course
'
,
),
),
]))),
]);
},
...
...
Frontend/src/UserSidebar.js
View file @
da0b678e
// User Sidebar
const
m
=
require
(
'
mithril
'
);
const
{
U
serCourses
}
=
require
(
'
./api.js
'
);
const
{
u
serCourses
}
=
require
(
'
./api.js
'
);
function
courseView
(
course
)
{
return
m
(
'
li
'
,
`
${
course
.
lecture
.
title
}
,
${
course
.
assistant
}
`
);
return
m
(
'
li
'
,
course
);
}
function
asList
(
courses
)
{
return
courses
.
map
(
courseView
);
}
module
.
exports
=
{
oninit
()
{
UserCourses
.
load
();
},
oninit
()
{
userCourses
.
get
();
},
view
()
{
return
[
m
(
'
h1
'
,
'
Selected Courses
'
),
UserCourses
.
selected
.
length
?
[
asList
(
UserCourses
.
selected
),
m
(
'
button
'
,
{
onclick
()
{
UserCourses
.
reserve
();
}
},
'
reserve
'
),
userCourses
.
selected
.
length
?
[
userCourses
.
selected
.
map
(
selId
=>
m
(
'
li
'
,
[
m
(
'
span
'
,
selId
),
m
(
'
button
'
,
{
onclick
()
{
userCourses
.
deselectCourse
(
selId
);
},
disabled
:
userCourses
.
resources
.
selections
.
isBusy
(),
},
'
X
'
,
),
])),
m
(
'
button
'
,
{
onclick
()
{
userCourses
.
reserve
();
}
},
'
reserve
'
),
]
:
m
(
'
p
'
,
'
No courses selected.
'
),
m
(
'
h1
'
,
'
Reserved Courses
'
),
U
serCourses
.
reserved
.
length
?
[
asList
(
U
serCourses
.
reserved
),
m
(
'
button
'
,
{
onclick
()
{
U
serCourses
.
pay
();
}
},
'
Pay
'
),
u
serCourses
.
reserved
.
length
?
[
asList
(
u
serCourses
.
reserved
),
m
(
'
button
'
,
{
onclick
()
{
u
serCourses
.
pay
();
}
},
'
Pay
'
),
]
:
m
(
'
p
'
,
'
No courses reserved.
'
),
m
(
'
h1
'
,
'
Accepted Courses
'
),
U
serCourses
.
accepted
.
length
?
[
asList
(
U
serCourses
.
accepted
),
u
serCourses
.
accepted
.
length
?
[
asList
(
u
serCourses
.
accepted
),
]
:
m
(
'
p
'
,
'
No courses accepted.
'
),
];
},
...
...
Frontend/src/api.js
View file @
da0b678e
...
...
@@ -137,9 +137,18 @@ const Session = {
};
// Helper to filter temp out of list
function
withoutTemp
(
list
,
temp
)
{
return
list
.
filter
(
item
=>
item
!==
temp
);
}
// Request to the PVK backend
function
request
({
resource
,
method
=
'
GET
'
,
id
=
''
,
data
=
{},
query
=
{},
resource
,
method
=
'
GET
'
,
id
=
''
,
data
=
{},
query
=
{},
headers
=
{},
})
{
// Parse query such that the backend understands it
const
parsedQuery
=
{};
...
...
@@ -148,18 +157,24 @@ function request({
});
const
queryString
=
m
.
buildQueryString
(
parsedQuery
);
const
allHeaders
=
Object
.
assign
(
{},
{
Authorization
:
`Token
${
Session
.
data
.
token
}
`
},
headers
,
);
// Send the request
return
m
.
request
({
method
,
data
,
url
:
`
${
pvkApiUrl
}
/
${
resource
}
/
${
id
}
?
${
queryString
}
`
,
headers
:
{
Authorization
:
`Token
${
Session
.
data
.
token
}
`
}
,
headers
:
allHeaders
,
}).
catch
((
err
)
=>
{
// If the error is 401, the token is invalid -> auto log out
if
(
err
.
_error
.
code
===
401
)
{
Session
.
clear
();
}
//
Actual error information is in the '_error' field, pass this on
throw
err
.
_error
;
//
Pass on Error
throw
err
;
});
}
...
...
@@ -168,22 +183,117 @@ function request({
class
Resource
{
constructor
(
name
,
query
=
{})
{
this
.
name
=
name
;
this
.
list
=
[];
this
.
query
=
query
;
// List for items confirmend by api
this
.
_items
=
{};
// Temporary objects to react instantly to requests
this
.
_items_new
=
[];
this
.
_items_updated
=
{};
this
.
_items_deleted
=
[];
}
load
()
{
return
request
({
resource
:
this
.
name
,
query
:
this
.
query
}).
then
((
data
)
=>
{
isBusy
()
{
return
Object
.
keys
(
this
.
_items_updated
).
length
!==
0
||
this
.
_items_deleted
.
length
!==
0
;
}
get
list
()
{
const
currentItems
=
Object
.
keys
(
this
.
_items
)
.
filter
(
key
=>
this
.
_items_deleted
.
indexOf
(
key
)
===
-
1
)
.
map
(
key
=>
this
.
_items_updated
[
key
]
||
this
.
_items
[
key
]);
return
[...
currentItems
,
...
this
.
_items_new
];
}
get
()
{
return
request
({
resource
:
this
.
name
,
query
:
this
.
query
,
}).
then
((
data
)
=>
{
// Fill own list
this
.
list
=
data
.
_items
;
this
.
_items
=
{};
data
.
_items
.
forEach
((
item
)
=>
{
this
.
_items
[
item
.
_id
]
=
item
;
});
// Pass on data
return
data
;
});
}
post
(
data
)
{
// Add data already to list of unprocessed items
this
.
_items_new
.
push
(
data
);
// Send request, remove temporary object as soon as response arrives
return
request
({
resource
:
this
.
name
,
method
:
'
POST
'
,
data
,
}).
then
((
confirmedData
)
=>
{
// Success!
this
.
_items_new
=
withoutTemp
(
this
.
_items_new
,
data
);
this
.
_items
[
confirmedData
.
_id
]
=
confirmedData
;
return
confirmedData
;
}).
catch
((
err
)
=>
{
this
.
_items_new
=
withoutTemp
(
this
.
_items_new
,
data
);
throw
err
;
});
}
patchItem
(
id
,
changes
)
{
// Add changes to temporary storage
this
.
_items_updated
[
id
]
=
Object
.
assign
(
{},
this
.
_items
[
id
],
changes
,
);
// Send request, remove temporary object as soon as response arrives
return
request
({
resource
:
this
.
name
,
id
,
method
:
'
PATCH
'
,
headers
:
{
'
If-Match
'
:
this
.
_items
[
id
].
_etag
},
data
:
changes
,
}).
then
((
confirmedData
)
=>
{
// Remove item
this
.
_items
[
id
]
=
confirmedData
;
delete
this
.
_items_updated
[
id
];
}).
catch
((
err
)
=>
{
// If 412: Data is outdated, reload!
if
(
err
.
_error
.
code
===
412
)
{
this
.
get
();
}
delete
this
.
_items_updated
[
id
];
throw
err
;
});
}
deleteItem
(
id
)
{
// Set item id on deleted-list
this
.
_items_deleted
.
push
(
id
);
// Send request, remove temporary object as soon as response arrives
return
request
({
resource
:
this
.
name
,
id
,
method
:
'
DELETE
'
,
headers
:
{
'
If-Match
'
:
this
.
_items
[
id
].
_etag
},
}).
then
((
result
)
=>
{
// Remove item
delete
this
.
_items
[
id
];
this
.
_items_deleted
=
withoutTemp
(
this
.
_items_deleted
,
id
);
return
result
;
}).
catch
((
err
)
=>
{
// If 412: Data is outdated, reload!
if
(
err
.
_error
.
code
===
412
)
{
this
.
get
();
}
this
.
_items_deleted
=
withoutTemp
(
this
.
_items_deleted
,
id
);
throw
err
;
});
}
}
const
userCourses
=
{
const
UserCourses
=
{
resources
:
{
selections
:
new
Resource
(
'
selections
'
,
...
...
@@ -195,15 +305,16 @@ const UserCourses = {
),
},
load
()
{
this
.
resources
.
selections
.
load
().
then
(()
=>
{
// We are only interested in one the first (and single) element
this
.
resources
.
selections
.
list
=
this
.
resources
.
selections
.
list
[
0
]
||
[];
});
this
.
resources
.
signups
.
load
();
get
()
{
this
.
resources
.
selections
.
get
();
this
.
resources
.
signups
.
get
();
},
get
selected
()
{
return
this
.
resources
.
selections
.
list
;
},
get
selected
()
{
// We are only interested in the first (only) item
const
sel
=
this
.
resources
.
selections
.
list
[
0
];
return
sel
?
sel
.
courses
:
[];
},
get
reserved
()
{
return
this
.
resources
.
signups
.
list
.
filter
(({
status
})
=>
status
===
'
reserved
'
);
...
...
@@ -213,18 +324,58 @@ const UserCourses = {
status
===
'
accepted
'
);
},
// TODO(Alex)
select
()
{},
selectCourse
(
courseId
)
{
// If user already has a selection and update it
const
currentSelection
=
this
.
resources
.
selections
.
list
[
0
]
||
[];
if
(
this
.
selected
.
length
>
0
)
{
const
selectionId
=
currentSelection
.
_id
;
const
newSelection
=
[
...
currentSelection
.
courses
,
courseId
,
];
return
this
.
resources
.
selections
.
patchItem
(
selectionId
,
{
courses
:
newSelection
},
);
// TODO: Provide error feedback to user in .catch
}
// Otherwise create a new selection
return
this
.
resources
.
selections
.
post
({
nethz
:
Session
.
user
.
nethz
,
courses
:
[
courseId
],
});
},
deselectCourse
(
courseId
)
{
const
selection
=
this
.
resources
.
selections
.
list
[
0
]
||
[];
const
newSelection
=
selection
.
courses
.
filter
(
item
=>
item
!==
courseId
);
const
selectionId
=
selection
.
_id
;
if
(
newSelection
.
length
===
0
)
{
this
.
resources
.
selections
.
deleteItem
(
selectionId
)
.
then
((
res
)
=>
{
console
.
log
(
res
);
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
});
}
else
{
this
.
resources
.
selections
.
patchItem
(
selectionId
,
{
courses
:
newSelection
},
);
}
// TODO: Provide error feedback to user in .catch
},
reserve
()
{},
pay
()
{},
};
const
C
ourses
=
new
Resource
(
'
courses
'
,
{
embedded
:
{
lecture
:
1
}
});
const
c
ourses
=
new
Resource
(
'
courses
'
,
{
embedded
:
{
lecture
:
1
}
});
const
lectures
=
new
Resource
(
'
lectures
'
);
module
.
exports
=
{
Session
,
request
,
UserCourses
,
Courses
,
userCourses
,
courses
,
lectures
,
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment