Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
8a5a4f33
Commit
8a5a4f33
authored
Sep 18, 2016
by
xiaoyu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix #14
parent
8cdc4674
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
110 additions
and
24 deletions
+110
-24
style.css
apps/static/css/style.css
+2
-2
toastr.js.map
apps/static/js/plugins/toastr/toastr.js.map
+0
-2
toastr.min.js
apps/static/js/plugins/toastr/toastr.min.js
+0
-1
base.html
apps/templates/base.html
+21
-3
api.py
apps/users/api.py
+13
-2
forms.py
apps/users/forms.py
+3
-1
models.py
apps/users/models.py
+1
-0
serializers.py
apps/users/serializers.py
+14
-7
_user_update_pk_modal.html
apps/users/templates/users/_user_update_pk_modal.html
+4
-4
first_login.html
apps/users/templates/users/first_login.html
+2
-0
user_detail.html
apps/users/templates/users/user_detail.html
+36
-0
urls.py
apps/users/urls.py
+1
-0
views.py
apps/users/views.py
+13
-2
No files found.
apps/static/css/style.css
View file @
8a5a4f33
@import
url("https://fonts.
useso
.com/css?family=Open+Sans:300,400,600,700")
;
@import
url("https://fonts.
googleapis
.com/css?family=Open+Sans:300,400,600,700")
;
@import
url("https://fonts.
useso
.com/css?family=Roboto:400,300,500,700")
;
@import
url("https://fonts.
googleapis
.com/css?family=Roboto:400,300,500,700")
;
/*
/*
*
*
* INSPINIA - Responsive Admin Theme
* INSPINIA - Responsive Admin Theme
...
...
apps/static/js/plugins/toastr/toastr.js.map
deleted
100644 → 0
View file @
8cdc4674
{"version":3,"sources":["toastr.js"],"names":["define","$","error","message","title","optionsOverride","notify","type","toastType","iconClass","getOptions","iconClasses","getContainer","options","create","$container","containerId","length","createContainer","info","subscribe","callback","listener","success","warning","clear","$toastElement","clearOptions","clearToast","clearContainer","remove","removeToast","children","toastsToClear","i","force","hideMethod","duration","hideDuration","easing","hideEasing","complete","attr","addClass","positionClass","appendTo","target","getDefaults","tapToDismiss","toastClass","debug","showMethod","showDuration","showEasing","onShown","undefined","onHidden","closeMethod","closeDuration","closeEasing","closeOnHover","extendedTimeOut","timeOut","titleClass","messageClass","escapeHtml","closeHtml","closeClass","newestOnTop","preventDuplicates","progressBar","progressClass","rtl","publish","args","map","source","replace","personalizeToast","setIcon","setTitle","setMessage","setCloseButton","setProgressBar","setRTL","setSequence","setAria","ariaValue","handleEvents","hover","stickAround","delayedHideToast","onclick","click","hideToast","closeButton","$closeElement","event","stopPropagation","cancelBubble","onCloseClick","displayToast","hide","intervalId","setTimeout","maxHideTime","parseFloat","hideEta","Date","getTime","setInterval","updateProgress","prepend","append","suffix","$titleElement","$messageElement","$progressElement","shouldExit","previousToast","override","method","clearTimeout","response","state","endTime","stop","percentage","width","extend","toastId","startTime","console","log","toastr","is","version","amd","deps","factory","module","exports","require","window","jQuery"],"mappings":"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","file":"toastr.js","sourcesContent":["/*\n * Toastr\n * Copyright 2012-2015\n * Authors: John Papa, Hans Fjällemark, and Tim Ferrell.\n * All Rights Reserved.\n * Use, reproduction, distribution, and modification of this code is subject to the terms and\n * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php\n *\n * ARIA Support: Greta Krafsig\n *\n * Project: https://github.com/CodeSeven/toastr\n */\n/* global define */\n(function (define) {\n define(['jquery'], function ($) {\n return (function () {\n var $container;\n var listener;\n var toastId = 0;\n var toastType = {\n error: 'error',\n info: 'info',\n success: 'success',\n warning: 'warning'\n };\n\n var toastr = {\n clear: clear,\n remove: remove,\n error: error,\n getContainer: getContainer,\n info: info,\n options: {},\n subscribe: subscribe,\n success: success,\n version: '2.1.3',\n warning: warning\n };\n\n var previousToast;\n\n return toastr;\n\n ////////////////\n\n function error(message, title, optionsOverride) {\n return notify({\n type: toastType.error,\n iconClass: getOptions().iconClasses.error,\n message: message,\n optionsOverride: optionsOverride,\n title: title\n });\n }\n\n function getContainer(options, create) {\n if (!options) { options = getOptions(); }\n $container = $('#' + options.containerId);\n if ($container.length) {\n return $container;\n }\n if (create) {\n $container = createContainer(options);\n }\n return $container;\n }\n\n function info(message, title, optionsOverride) {\n return notify({\n type: toastType.info,\n iconClass: getOptions().iconClasses.info,\n message: message,\n optionsOverride: optionsOverride,\n title: title\n });\n }\n\n function subscribe(callback) {\n listener = callback;\n }\n\n function success(message, title, optionsOverride) {\n return notify({\n type: toastType.success,\n iconClass: getOptions().iconClasses.success,\n message: message,\n optionsOverride: optionsOverride,\n title: title\n });\n }\n\n function warning(message, title, optionsOverride) {\n return notify({\n type: toastType.warning,\n iconClass: getOptions().iconClasses.warning,\n message: message,\n optionsOverride: optionsOverride,\n title: title\n });\n }\n\n function clear($toastElement, clearOptions) {\n var options = getOptions();\n if (!$container) { getContainer(options); }\n if (!clearToast($toastElement, options, clearOptions)) {\n clearContainer(options);\n }\n }\n\n function remove($toastElement) {\n var options = getOptions();\n if (!$container) { getContainer(options); }\n if ($toastElement && $(':focus', $toastElement).length === 0) {\n removeToast($toastElement);\n return;\n }\n if ($container.children().length) {\n $container.remove();\n }\n }\n\n // internal functions\n\n function clearContainer (options) {\n var toastsToClear = $container.children();\n for (var i = toastsToClear.length - 1; i >= 0; i--) {\n clearToast($(toastsToClear[i]), options);\n }\n }\n\n function clearToast ($toastElement, options, clearOptions) {\n var force = clearOptions && clearOptions.force ? clearOptions.force : false;\n if ($toastElement && (force || $(':focus', $toastElement).length === 0)) {\n $toastElement[options.hideMethod]({\n duration: options.hideDuration,\n easing: options.hideEasing,\n complete: function () { removeToast($toastElement); }\n });\n return true;\n }\n return false;\n }\n\n function createContainer(options) {\n $container = $('<div/>')\n .attr('id', options.containerId)\n .addClass(options.positionClass);\n\n $container.appendTo($(options.target));\n return $container;\n }\n\n function getDefaults() {\n return {\n tapToDismiss: true,\n toastClass: 'toast',\n containerId: 'toast-container',\n debug: false,\n\n showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery\n showDuration: 300,\n showEasing: 'swing', //swing and linear are built into jQuery\n onShown: undefined,\n hideMethod: 'fadeOut',\n hideDuration: 1000,\n hideEasing: 'swing',\n onHidden: undefined,\n closeMethod: false,\n closeDuration: false,\n closeEasing: false,\n closeOnHover: true,\n\n extendedTimeOut: 1000,\n iconClasses: {\n error: 'toast-error',\n info: 'toast-info',\n success: 'toast-success',\n warning: 'toast-warning'\n },\n iconClass: 'toast-info',\n positionClass: 'toast-top-right',\n timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky\n titleClass: 'toast-title',\n messageClass: 'toast-message',\n escapeHtml: false,\n target: 'body',\n closeHtml: '<button type=\"button\">×</button>',\n closeClass: 'toast-close-button',\n newestOnTop: true,\n preventDuplicates: false,\n progressBar: false,\n progressClass: 'toast-progress',\n rtl: false\n };\n }\n\n function publish(args) {\n if (!listener) { return; }\n listener(args);\n }\n\n function notify(map) {\n var options = getOptions();\n var iconClass = map.iconClass || options.iconClass;\n\n if (typeof (map.optionsOverride) !== 'undefined') {\n options = $.extend(options, map.optionsOverride);\n iconClass = map.optionsOverride.iconClass || iconClass;\n }\n\n if (shouldExit(options, map)) { return; }\n\n toastId++;\n\n $container = getContainer(options, true);\n\n var intervalId = null;\n var $toastElement = $('<div/>');\n var $titleElement = $('<div/>');\n var $messageElement = $('<div/>');\n var $progressElement = $('<div/>');\n var $closeElement = $(options.closeHtml);\n var progressBar = {\n intervalId: null,\n hideEta: null,\n maxHideTime: null\n };\n var response = {\n toastId: toastId,\n state: 'visible',\n startTime: new Date(),\n options: options,\n map: map\n };\n\n personalizeToast();\n\n displayToast();\n\n handleEvents();\n\n publish(response);\n\n if (options.debug && console) {\n console.log(response);\n }\n\n return $toastElement;\n\n function escapeHtml(source) {\n if (source == null) {\n source = '';\n }\n\n return source\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n }\n\n function personalizeToast() {\n setIcon();\n setTitle();\n setMessage();\n setCloseButton();\n setProgressBar();\n setRTL();\n setSequence();\n setAria();\n }\n\n function setAria() {\n var ariaValue = '';\n switch (map.iconClass) {\n case 'toast-success':\n case 'toast-info':\n ariaValue = 'polite';\n break;\n default:\n ariaValue = 'assertive';\n }\n $toastElement.attr('aria-live', ariaValue);\n }\n\n function handleEvents() {\n if (options.closeOnHover) {\n $toastElement.hover(stickAround, delayedHideToast);\n }\n\n if (!options.onclick && options.tapToDismiss) {\n $toastElement.click(hideToast);\n }\n\n if (options.closeButton && $closeElement) {\n $closeElement.click(function (event) {\n if (event.stopPropagation) {\n event.stopPropagation();\n } else if (event.cancelBubble !== undefined && event.cancelBubble !== true) {\n event.cancelBubble = true;\n }\n\n if (options.onCloseClick) {\n options.onCloseClick(event);\n }\n\n hideToast(true);\n });\n }\n\n if (options.onclick) {\n $toastElement.click(function (event) {\n options.onclick(event);\n hideToast();\n });\n }\n }\n\n function displayToast() {\n $toastElement.hide();\n\n $toastElement[options.showMethod](\n {duration: options.showDuration, easing: options.showEasing, complete: options.onShown}\n );\n\n if (options.timeOut > 0) {\n intervalId = setTimeout(hideToast, options.timeOut);\n progressBar.maxHideTime = parseFloat(options.timeOut);\n progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;\n if (options.progressBar) {\n progressBar.intervalId = setInterval(updateProgress, 10);\n }\n }\n }\n\n function setIcon() {\n if (map.iconClass) {\n $toastElement.addClass(options.toastClass).addClass(iconClass);\n }\n }\n\n function setSequence() {\n if (options.newestOnTop) {\n $container.prepend($toastElement);\n } else {\n $container.append($toastElement);\n }\n }\n\n function setTitle() {\n if (map.title) {\n var suffix = map.title;\n if (options.escapeHtml) {\n suffix = escapeHtml(map.title);\n }\n $titleElement.append(suffix).addClass(options.titleClass);\n $toastElement.append($titleElement);\n }\n }\n\n function setMessage() {\n if (map.message) {\n var suffix = map.message;\n if (options.escapeHtml) {\n suffix = escapeHtml(map.message);\n }\n $messageElement.append(suffix).addClass(options.messageClass);\n $toastElement.append($messageElement);\n }\n }\n\n function setCloseButton() {\n if (options.closeButton) {\n $closeElement.addClass(options.closeClass).attr('role', 'button');\n $toastElement.prepend($closeElement);\n }\n }\n\n function setProgressBar() {\n if (options.progressBar) {\n $progressElement.addClass(options.progressClass);\n $toastElement.prepend($progressElement);\n }\n }\n\n function setRTL() {\n if (options.rtl) {\n $toastElement.addClass('rtl');\n }\n }\n\n function shouldExit(options, map) {\n if (options.preventDuplicates) {\n if (map.message === previousToast) {\n return true;\n } else {\n previousToast = map.message;\n }\n }\n return false;\n }\n\n function hideToast(override) {\n var method = override && options.closeMethod !== false ? options.closeMethod : options.hideMethod;\n var duration = override && options.closeDuration !== false ?\n options.closeDuration : options.hideDuration;\n var easing = override && options.closeEasing !== false ? options.closeEasing : options.hideEasing;\n if ($(':focus', $toastElement).length && !override) {\n return;\n }\n clearTimeout(progressBar.intervalId);\n return $toastElement[method]({\n duration: duration,\n easing: easing,\n complete: function () {\n removeToast($toastElement);\n clearTimeout(intervalId);\n if (options.onHidden && response.state !== 'hidden') {\n options.onHidden();\n }\n response.state = 'hidden';\n response.endTime = new Date();\n publish(response);\n }\n });\n }\n\n function delayedHideToast() {\n if (options.timeOut > 0 || options.extendedTimeOut > 0) {\n intervalId = setTimeout(hideToast, options.extendedTimeOut);\n progressBar.maxHideTime = parseFloat(options.extendedTimeOut);\n progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;\n }\n }\n\n function stickAround() {\n clearTimeout(intervalId);\n progressBar.hideEta = 0;\n $toastElement.stop(true, true)[options.showMethod](\n {duration: options.showDuration, easing: options.showEasing}\n );\n }\n\n function updateProgress() {\n var percentage = ((progressBar.hideEta - (new Date().getTime())) / progressBar.maxHideTime) * 100;\n $progressElement.width(percentage + '%');\n }\n }\n\n function getOptions() {\n return $.extend({}, getDefaults(), toastr.options);\n }\n\n function removeToast($toastElement) {\n if (!$container) { $container = getContainer(); }\n if ($toastElement.is(':visible')) {\n return;\n }\n $toastElement.remove();\n $toastElement = null;\n if ($container.children().length === 0) {\n $container.remove();\n previousToast = undefined;\n }\n }\n\n })();\n });\n}(typeof define === 'function' && define.amd ? define : function (deps, factory) {\n if (typeof module !== 'undefined' && module.exports) { //Node\n module.exports = factory(require('jquery'));\n } else {\n window.toastr = factory(window.jQuery);\n }\n}));\n"],"sourceRoot":"/source/"}
\ No newline at end of file
apps/static/js/plugins/toastr/toastr.min.js
View file @
8a5a4f33
!
function
(
e
){
e
([
"jquery"
],
function
(
e
){
return
function
(){
function
t
(
e
,
t
,
n
){
return
g
({
type
:
O
.
error
,
iconClass
:
m
().
iconClasses
.
error
,
message
:
e
,
optionsOverride
:
n
,
title
:
t
})}
function
n
(
t
,
n
){
return
t
||
(
t
=
m
()),
v
=
e
(
"#"
+
t
.
containerId
),
v
.
length
?
v
:(
n
&&
(
v
=
d
(
t
)),
v
)}
function
o
(
e
,
t
,
n
){
return
g
({
type
:
O
.
info
,
iconClass
:
m
().
iconClasses
.
info
,
message
:
e
,
optionsOverride
:
n
,
title
:
t
})}
function
s
(
e
){
C
=
e
}
function
i
(
e
,
t
,
n
){
return
g
({
type
:
O
.
success
,
iconClass
:
m
().
iconClasses
.
success
,
message
:
e
,
optionsOverride
:
n
,
title
:
t
})}
function
a
(
e
,
t
,
n
){
return
g
({
type
:
O
.
warning
,
iconClass
:
m
().
iconClasses
.
warning
,
message
:
e
,
optionsOverride
:
n
,
title
:
t
})}
function
r
(
e
,
t
){
var
o
=
m
();
v
||
n
(
o
),
u
(
e
,
o
,
t
)
||
l
(
o
)}
function
c
(
t
){
var
o
=
m
();
return
v
||
n
(
o
),
t
&&
0
===
e
(
":focus"
,
t
).
length
?
void
h
(
t
):
void
(
v
.
children
().
length
&&
v
.
remove
())}
function
l
(
t
){
for
(
var
n
=
v
.
children
(),
o
=
n
.
length
-
1
;
o
>=
0
;
o
--
)
u
(
e
(
n
[
o
]),
t
)}
function
u
(
t
,
n
,
o
){
var
s
=!
(
!
o
||!
o
.
force
)
&&
o
.
force
;
return
!
(
!
t
||!
s
&&
0
!==
e
(
":focus"
,
t
).
length
)
&&
(
t
[
n
.
hideMethod
]({
duration
:
n
.
hideDuration
,
easing
:
n
.
hideEasing
,
complete
:
function
(){
h
(
t
)}}),
!
0
)}
function
d
(
t
){
return
v
=
e
(
"<div/>"
).
attr
(
"id"
,
t
.
containerId
).
addClass
(
t
.
positionClass
),
v
.
appendTo
(
e
(
t
.
target
)),
v
}
function
p
(){
return
{
tapToDismiss
:
!
0
,
toastClass
:
"toast"
,
containerId
:
"toast-container"
,
debug
:
!
1
,
showMethod
:
"fadeIn"
,
showDuration
:
300
,
showEasing
:
"swing"
,
onShown
:
void
0
,
hideMethod
:
"fadeOut"
,
hideDuration
:
1
e3
,
hideEasing
:
"swing"
,
onHidden
:
void
0
,
closeMethod
:
!
1
,
closeDuration
:
!
1
,
closeEasing
:
!
1
,
closeOnHover
:
!
0
,
extendedTimeOut
:
1
e3
,
iconClasses
:{
error
:
"toast-error"
,
info
:
"toast-info"
,
success
:
"toast-success"
,
warning
:
"toast-warning"
},
iconClass
:
"toast-info"
,
positionClass
:
"toast-top-right"
,
timeOut
:
5
e3
,
titleClass
:
"toast-title"
,
messageClass
:
"toast-message"
,
escapeHtml
:
!
1
,
target
:
"body"
,
closeHtml
:
'<button type="button">×</button>'
,
closeClass
:
"toast-close-button"
,
newestOnTop
:
!
0
,
preventDuplicates
:
!
1
,
progressBar
:
!
1
,
progressClass
:
"toast-progress"
,
rtl
:
!
1
}}
function
f
(
e
){
C
&&
C
(
e
)}
function
g
(
t
){
function
o
(
e
){
return
null
==
e
&&
(
e
=
""
),
e
.
replace
(
/&/g
,
"&"
).
replace
(
/"/g
,
"""
).
replace
(
/'/g
,
"'"
).
replace
(
/</g
,
"<"
).
replace
(
/>/g
,
">"
)}
function
s
(){
c
(),
u
(),
d
(),
p
(),
g
(),
C
(),
l
(),
i
()}
function
i
(){
var
e
=
""
;
switch
(
t
.
iconClass
){
case
"toast-success"
:
case
"toast-info"
:
e
=
"polite"
;
break
;
default
:
e
=
"assertive"
}
I
.
attr
(
"aria-live"
,
e
)}
function
a
(){
E
.
closeOnHover
&&
I
.
hover
(
H
,
D
),
!
E
.
onclick
&&
E
.
tapToDismiss
&&
I
.
click
(
b
),
E
.
closeButton
&&
j
&&
j
.
click
(
function
(
e
){
e
.
stopPropagation
?
e
.
stopPropagation
():
void
0
!==
e
.
cancelBubble
&&
e
.
cancelBubble
!==!
0
&&
(
e
.
cancelBubble
=!
0
),
E
.
onCloseClick
&&
E
.
onCloseClick
(
e
),
b
(
!
0
)}),
E
.
onclick
&&
I
.
click
(
function
(
e
){
E
.
onclick
(
e
),
b
()})}
function
r
(){
I
.
hide
(),
I
[
E
.
showMethod
]({
duration
:
E
.
showDuration
,
easing
:
E
.
showEasing
,
complete
:
E
.
onShown
}),
E
.
timeOut
>
0
&&
(
k
=
setTimeout
(
b
,
E
.
timeOut
),
F
.
maxHideTime
=
parseFloat
(
E
.
timeOut
),
F
.
hideEta
=
(
new
Date
).
getTime
()
+
F
.
maxHideTime
,
E
.
progressBar
&&
(
F
.
intervalId
=
setInterval
(
x
,
10
)))}
function
c
(){
t
.
iconClass
&&
I
.
addClass
(
E
.
toastClass
).
addClass
(
y
)}
function
l
(){
E
.
newestOnTop
?
v
.
prepend
(
I
):
v
.
append
(
I
)}
function
u
(){
if
(
t
.
title
){
var
e
=
t
.
title
;
E
.
escapeHtml
&&
(
e
=
o
(
t
.
title
)),
M
.
append
(
e
).
addClass
(
E
.
titleClass
),
I
.
append
(
M
)}}
function
d
(){
if
(
t
.
message
){
var
e
=
t
.
message
;
E
.
escapeHtml
&&
(
e
=
o
(
t
.
message
)),
B
.
append
(
e
).
addClass
(
E
.
messageClass
),
I
.
append
(
B
)}}
function
p
(){
E
.
closeButton
&&
(
j
.
addClass
(
E
.
closeClass
).
attr
(
"role"
,
"button"
),
I
.
prepend
(
j
))}
function
g
(){
E
.
progressBar
&&
(
q
.
addClass
(
E
.
progressClass
),
I
.
prepend
(
q
))}
function
C
(){
E
.
rtl
&&
I
.
addClass
(
"rtl"
)}
function
O
(
e
,
t
){
if
(
e
.
preventDuplicates
){
if
(
t
.
message
===
w
)
return
!
0
;
w
=
t
.
message
}
return
!
1
}
function
b
(
t
){
var
n
=
t
&&
E
.
closeMethod
!==!
1
?
E
.
closeMethod
:
E
.
hideMethod
,
o
=
t
&&
E
.
closeDuration
!==!
1
?
E
.
closeDuration
:
E
.
hideDuration
,
s
=
t
&&
E
.
closeEasing
!==!
1
?
E
.
closeEasing
:
E
.
hideEasing
;
if
(
!
e
(
":focus"
,
I
).
length
||
t
)
return
clearTimeout
(
F
.
intervalId
),
I
[
n
]({
duration
:
o
,
easing
:
s
,
complete
:
function
(){
h
(
I
),
clearTimeout
(
k
),
E
.
onHidden
&&
"hidden"
!==
P
.
state
&&
E
.
onHidden
(),
P
.
state
=
"hidden"
,
P
.
endTime
=
new
Date
,
f
(
P
)}})}
function
D
(){(
E
.
timeOut
>
0
||
E
.
extendedTimeOut
>
0
)
&&
(
k
=
setTimeout
(
b
,
E
.
extendedTimeOut
),
F
.
maxHideTime
=
parseFloat
(
E
.
extendedTimeOut
),
F
.
hideEta
=
(
new
Date
).
getTime
()
+
F
.
maxHideTime
)}
function
H
(){
clearTimeout
(
k
),
F
.
hideEta
=
0
,
I
.
stop
(
!
0
,
!
0
)[
E
.
showMethod
]({
duration
:
E
.
showDuration
,
easing
:
E
.
showEasing
})}
function
x
(){
var
e
=
(
F
.
hideEta
-
(
new
Date
).
getTime
())
/
F
.
maxHideTime
*
100
;
q
.
width
(
e
+
"%"
)}
var
E
=
m
(),
y
=
t
.
iconClass
||
E
.
iconClass
;
if
(
"undefined"
!=
typeof
t
.
optionsOverride
&&
(
E
=
e
.
extend
(
E
,
t
.
optionsOverride
),
y
=
t
.
optionsOverride
.
iconClass
||
y
),
!
O
(
E
,
t
)){
T
++
,
v
=
n
(
E
,
!
0
);
var
k
=
null
,
I
=
e
(
"<div/>"
),
M
=
e
(
"<div/>"
),
B
=
e
(
"<div/>"
),
q
=
e
(
"<div/>"
),
j
=
e
(
E
.
closeHtml
),
F
=
{
intervalId
:
null
,
hideEta
:
null
,
maxHideTime
:
null
},
P
=
{
toastId
:
T
,
state
:
"visible"
,
startTime
:
new
Date
,
options
:
E
,
map
:
t
};
return
s
(),
r
(),
a
(),
f
(
P
),
E
.
debug
&&
console
&&
console
.
log
(
P
),
I
}}
function
m
(){
return
e
.
extend
({},
p
(),
b
.
options
)}
function
h
(
e
){
v
||
(
v
=
n
()),
e
.
is
(
":visible"
)
||
(
e
.
remove
(),
e
=
null
,
0
===
v
.
children
().
length
&&
(
v
.
remove
(),
w
=
void
0
))}
var
v
,
C
,
w
,
T
=
0
,
O
=
{
error
:
"error"
,
info
:
"info"
,
success
:
"success"
,
warning
:
"warning"
},
b
=
{
clear
:
r
,
remove
:
c
,
error
:
t
,
getContainer
:
n
,
info
:
o
,
options
:{},
subscribe
:
s
,
success
:
i
,
version
:
"2.1.3"
,
warning
:
a
};
return
b
}()})}(
"function"
==
typeof
define
&&
define
.
amd
?
define
:
function
(
e
,
t
){
"undefined"
!=
typeof
module
&&
module
.
exports
?
module
.
exports
=
t
(
require
(
"jquery"
)):
window
.
toastr
=
t
(
window
.
jQuery
)});
!
function
(
e
){
e
([
"jquery"
],
function
(
e
){
return
function
(){
function
t
(
e
,
t
,
n
){
return
g
({
type
:
O
.
error
,
iconClass
:
m
().
iconClasses
.
error
,
message
:
e
,
optionsOverride
:
n
,
title
:
t
})}
function
n
(
t
,
n
){
return
t
||
(
t
=
m
()),
v
=
e
(
"#"
+
t
.
containerId
),
v
.
length
?
v
:(
n
&&
(
v
=
d
(
t
)),
v
)}
function
o
(
e
,
t
,
n
){
return
g
({
type
:
O
.
info
,
iconClass
:
m
().
iconClasses
.
info
,
message
:
e
,
optionsOverride
:
n
,
title
:
t
})}
function
s
(
e
){
C
=
e
}
function
i
(
e
,
t
,
n
){
return
g
({
type
:
O
.
success
,
iconClass
:
m
().
iconClasses
.
success
,
message
:
e
,
optionsOverride
:
n
,
title
:
t
})}
function
a
(
e
,
t
,
n
){
return
g
({
type
:
O
.
warning
,
iconClass
:
m
().
iconClasses
.
warning
,
message
:
e
,
optionsOverride
:
n
,
title
:
t
})}
function
r
(
e
,
t
){
var
o
=
m
();
v
||
n
(
o
),
u
(
e
,
o
,
t
)
||
l
(
o
)}
function
c
(
t
){
var
o
=
m
();
return
v
||
n
(
o
),
t
&&
0
===
e
(
":focus"
,
t
).
length
?
void
h
(
t
):
void
(
v
.
children
().
length
&&
v
.
remove
())}
function
l
(
t
){
for
(
var
n
=
v
.
children
(),
o
=
n
.
length
-
1
;
o
>=
0
;
o
--
)
u
(
e
(
n
[
o
]),
t
)}
function
u
(
t
,
n
,
o
){
var
s
=!
(
!
o
||!
o
.
force
)
&&
o
.
force
;
return
!
(
!
t
||!
s
&&
0
!==
e
(
":focus"
,
t
).
length
)
&&
(
t
[
n
.
hideMethod
]({
duration
:
n
.
hideDuration
,
easing
:
n
.
hideEasing
,
complete
:
function
(){
h
(
t
)}}),
!
0
)}
function
d
(
t
){
return
v
=
e
(
"<div/>"
).
attr
(
"id"
,
t
.
containerId
).
addClass
(
t
.
positionClass
),
v
.
appendTo
(
e
(
t
.
target
)),
v
}
function
p
(){
return
{
tapToDismiss
:
!
0
,
toastClass
:
"toast"
,
containerId
:
"toast-container"
,
debug
:
!
1
,
showMethod
:
"fadeIn"
,
showDuration
:
300
,
showEasing
:
"swing"
,
onShown
:
void
0
,
hideMethod
:
"fadeOut"
,
hideDuration
:
1
e3
,
hideEasing
:
"swing"
,
onHidden
:
void
0
,
closeMethod
:
!
1
,
closeDuration
:
!
1
,
closeEasing
:
!
1
,
closeOnHover
:
!
0
,
extendedTimeOut
:
1
e3
,
iconClasses
:{
error
:
"toast-error"
,
info
:
"toast-info"
,
success
:
"toast-success"
,
warning
:
"toast-warning"
},
iconClass
:
"toast-info"
,
positionClass
:
"toast-top-right"
,
timeOut
:
5
e3
,
titleClass
:
"toast-title"
,
messageClass
:
"toast-message"
,
escapeHtml
:
!
1
,
target
:
"body"
,
closeHtml
:
'<button type="button">×</button>'
,
closeClass
:
"toast-close-button"
,
newestOnTop
:
!
0
,
preventDuplicates
:
!
1
,
progressBar
:
!
1
,
progressClass
:
"toast-progress"
,
rtl
:
!
1
}}
function
f
(
e
){
C
&&
C
(
e
)}
function
g
(
t
){
function
o
(
e
){
return
null
==
e
&&
(
e
=
""
),
e
.
replace
(
/&/g
,
"&"
).
replace
(
/"/g
,
"""
).
replace
(
/'/g
,
"'"
).
replace
(
/</g
,
"<"
).
replace
(
/>/g
,
">"
)}
function
s
(){
c
(),
u
(),
d
(),
p
(),
g
(),
C
(),
l
(),
i
()}
function
i
(){
var
e
=
""
;
switch
(
t
.
iconClass
){
case
"toast-success"
:
case
"toast-info"
:
e
=
"polite"
;
break
;
default
:
e
=
"assertive"
}
I
.
attr
(
"aria-live"
,
e
)}
function
a
(){
E
.
closeOnHover
&&
I
.
hover
(
H
,
D
),
!
E
.
onclick
&&
E
.
tapToDismiss
&&
I
.
click
(
b
),
E
.
closeButton
&&
j
&&
j
.
click
(
function
(
e
){
e
.
stopPropagation
?
e
.
stopPropagation
():
void
0
!==
e
.
cancelBubble
&&
e
.
cancelBubble
!==!
0
&&
(
e
.
cancelBubble
=!
0
),
E
.
onCloseClick
&&
E
.
onCloseClick
(
e
),
b
(
!
0
)}),
E
.
onclick
&&
I
.
click
(
function
(
e
){
E
.
onclick
(
e
),
b
()})}
function
r
(){
I
.
hide
(),
I
[
E
.
showMethod
]({
duration
:
E
.
showDuration
,
easing
:
E
.
showEasing
,
complete
:
E
.
onShown
}),
E
.
timeOut
>
0
&&
(
k
=
setTimeout
(
b
,
E
.
timeOut
),
F
.
maxHideTime
=
parseFloat
(
E
.
timeOut
),
F
.
hideEta
=
(
new
Date
).
getTime
()
+
F
.
maxHideTime
,
E
.
progressBar
&&
(
F
.
intervalId
=
setInterval
(
x
,
10
)))}
function
c
(){
t
.
iconClass
&&
I
.
addClass
(
E
.
toastClass
).
addClass
(
y
)}
function
l
(){
E
.
newestOnTop
?
v
.
prepend
(
I
):
v
.
append
(
I
)}
function
u
(){
if
(
t
.
title
){
var
e
=
t
.
title
;
E
.
escapeHtml
&&
(
e
=
o
(
t
.
title
)),
M
.
append
(
e
).
addClass
(
E
.
titleClass
),
I
.
append
(
M
)}}
function
d
(){
if
(
t
.
message
){
var
e
=
t
.
message
;
E
.
escapeHtml
&&
(
e
=
o
(
t
.
message
)),
B
.
append
(
e
).
addClass
(
E
.
messageClass
),
I
.
append
(
B
)}}
function
p
(){
E
.
closeButton
&&
(
j
.
addClass
(
E
.
closeClass
).
attr
(
"role"
,
"button"
),
I
.
prepend
(
j
))}
function
g
(){
E
.
progressBar
&&
(
q
.
addClass
(
E
.
progressClass
),
I
.
prepend
(
q
))}
function
C
(){
E
.
rtl
&&
I
.
addClass
(
"rtl"
)}
function
O
(
e
,
t
){
if
(
e
.
preventDuplicates
){
if
(
t
.
message
===
w
)
return
!
0
;
w
=
t
.
message
}
return
!
1
}
function
b
(
t
){
var
n
=
t
&&
E
.
closeMethod
!==!
1
?
E
.
closeMethod
:
E
.
hideMethod
,
o
=
t
&&
E
.
closeDuration
!==!
1
?
E
.
closeDuration
:
E
.
hideDuration
,
s
=
t
&&
E
.
closeEasing
!==!
1
?
E
.
closeEasing
:
E
.
hideEasing
;
if
(
!
e
(
":focus"
,
I
).
length
||
t
)
return
clearTimeout
(
F
.
intervalId
),
I
[
n
]({
duration
:
o
,
easing
:
s
,
complete
:
function
(){
h
(
I
),
clearTimeout
(
k
),
E
.
onHidden
&&
"hidden"
!==
P
.
state
&&
E
.
onHidden
(),
P
.
state
=
"hidden"
,
P
.
endTime
=
new
Date
,
f
(
P
)}})}
function
D
(){(
E
.
timeOut
>
0
||
E
.
extendedTimeOut
>
0
)
&&
(
k
=
setTimeout
(
b
,
E
.
extendedTimeOut
),
F
.
maxHideTime
=
parseFloat
(
E
.
extendedTimeOut
),
F
.
hideEta
=
(
new
Date
).
getTime
()
+
F
.
maxHideTime
)}
function
H
(){
clearTimeout
(
k
),
F
.
hideEta
=
0
,
I
.
stop
(
!
0
,
!
0
)[
E
.
showMethod
]({
duration
:
E
.
showDuration
,
easing
:
E
.
showEasing
})}
function
x
(){
var
e
=
(
F
.
hideEta
-
(
new
Date
).
getTime
())
/
F
.
maxHideTime
*
100
;
q
.
width
(
e
+
"%"
)}
var
E
=
m
(),
y
=
t
.
iconClass
||
E
.
iconClass
;
if
(
"undefined"
!=
typeof
t
.
optionsOverride
&&
(
E
=
e
.
extend
(
E
,
t
.
optionsOverride
),
y
=
t
.
optionsOverride
.
iconClass
||
y
),
!
O
(
E
,
t
)){
T
++
,
v
=
n
(
E
,
!
0
);
var
k
=
null
,
I
=
e
(
"<div/>"
),
M
=
e
(
"<div/>"
),
B
=
e
(
"<div/>"
),
q
=
e
(
"<div/>"
),
j
=
e
(
E
.
closeHtml
),
F
=
{
intervalId
:
null
,
hideEta
:
null
,
maxHideTime
:
null
},
P
=
{
toastId
:
T
,
state
:
"visible"
,
startTime
:
new
Date
,
options
:
E
,
map
:
t
};
return
s
(),
r
(),
a
(),
f
(
P
),
E
.
debug
&&
console
&&
console
.
log
(
P
),
I
}}
function
m
(){
return
e
.
extend
({},
p
(),
b
.
options
)}
function
h
(
e
){
v
||
(
v
=
n
()),
e
.
is
(
":visible"
)
||
(
e
.
remove
(),
e
=
null
,
0
===
v
.
children
().
length
&&
(
v
.
remove
(),
w
=
void
0
))}
var
v
,
C
,
w
,
T
=
0
,
O
=
{
error
:
"error"
,
info
:
"info"
,
success
:
"success"
,
warning
:
"warning"
},
b
=
{
clear
:
r
,
remove
:
c
,
error
:
t
,
getContainer
:
n
,
info
:
o
,
options
:{},
subscribe
:
s
,
success
:
i
,
version
:
"2.1.3"
,
warning
:
a
};
return
b
}()})}(
"function"
==
typeof
define
&&
define
.
amd
?
define
:
function
(
e
,
t
){
"undefined"
!=
typeof
module
&&
module
.
exports
?
module
.
exports
=
t
(
require
(
"jquery"
)):
window
.
toastr
=
t
(
window
.
jQuery
)});
//# sourceMappingURL=toastr.js.map
apps/templates/base.html
View file @
8a5a4f33
{% load static %}
{% load static
i18n
%}
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<html>
<head>
<head>
...
@@ -20,6 +20,25 @@
...
@@ -20,6 +20,25 @@
<div
id=
"page-wrapper"
class=
"gray-bg"
>
<div
id=
"page-wrapper"
class=
"gray-bg"
>
{% include '_header_bar.html' %}
{% include '_header_bar.html' %}
{% include '_message.html' %}
{% include '_message.html' %}
{% block first_login_message %}
{% if user.is_authenticated and user.is_first_login %}
<div
class=
"alert alert-danger"
style=
"margin: 20px auto 0px"
>
{% url 'users:user-first-login' as the_url %}
{% blocktrans %}
Your information was incomplete. Please click
<a
href=
"{{ the_url }}"
>
this link
</a>
to complete your information.
{% endblocktrans %}
</div>
{% endif %}
{% endblock %}
{% block update_public_key_message %}
{% if user.is_authenticated and not user.is_public_key_valid %}
<div
class=
"alert alert-danger"
style=
"margin: 20px auto 0px"
>
{% blocktrans %}
Your ssh-public-key has been expired. Please click
<a
href=
"#"
>
this link
</a>
to update your ssh-public-key.
{% endblocktrans %}
</div>
{% endif %}
{% endblock %}
{% block content %}{% endblock %}
{% block content %}{% endblock %}
{% include '_footer.html' %}
{% include '_footer.html' %}
</div>
</div>
...
@@ -28,4 +47,4 @@
...
@@ -28,4 +47,4 @@
</body>
</body>
{% include '_foot_js.html' %}
{% include '_foot_js.html' %}
{% block custom_foot_js %} {% endblock %}
{% block custom_foot_js %} {% endblock %}
</html>
</html>
\ No newline at end of file
apps/users/api.py
View file @
8a5a4f33
...
@@ -5,7 +5,8 @@ import logging
...
@@ -5,7 +5,8 @@ import logging
from
rest_framework
import
generics
from
rest_framework
import
generics
from
.serializers
import
UserSerializer
,
UserGroupSerializer
,
UserAttributeSerializer
,
UserGroupEditSerializer
from
.serializers
import
UserSerializer
,
UserGroupSerializer
,
UserAttributeSerializer
,
UserGroupEditSerializer
,
\
UserPKUpdateSerializer
from
.models
import
User
,
UserGroup
from
.models
import
User
,
UserGroup
...
@@ -72,7 +73,17 @@ class UserResetPKApi(generics.UpdateAPIView):
...
@@ -72,7 +73,17 @@ class UserResetPKApi(generics.UpdateAPIView):
def
perform_update
(
self
,
serializer
):
def
perform_update
(
self
,
serializer
):
user
=
self
.
get_object
()
user
=
self
.
get_object
()
user
.
_public_key
=
''
user
.
is_public_key_valid
=
False
user
.
save
()
user
.
save
()
from
.utils
import
send_reset_ssh_key_mail
from
.utils
import
send_reset_ssh_key_mail
send_reset_ssh_key_mail
(
user
)
send_reset_ssh_key_mail
(
user
)
class
UserUpdatePKApi
(
generics
.
UpdateAPIView
):
queryset
=
User
.
objects
.
all
()
serializer_class
=
UserPKUpdateSerializer
def
perform_update
(
self
,
serializer
):
user
=
self
.
get_object
()
user
.
private_key
=
serializer
.
validated_data
[
'_public_key'
]
user
.
save
()
apps/users/forms.py
View file @
8a5a4f33
...
@@ -79,9 +79,11 @@ class UserKeyForm(forms.Form):
...
@@ -79,9 +79,11 @@ class UserKeyForm(forms.Form):
help_text
=
_
(
'Paste your id_ras.pub here.'
))
help_text
=
_
(
'Paste your id_ras.pub here.'
))
def
clean_public_key
(
self
):
def
clean_public_key
(
self
):
public_key
=
self
.
cleaned_data
[
'public_key'
]
if
self
.
user
.
_public_key
and
public_key
==
self
.
user
.
public_key
:
raise
forms
.
ValidationError
(
_
(
'Public key should not be the same as your old one.'
))
from
sshpubkeys
import
SSHKey
from
sshpubkeys
import
SSHKey
from
sshpubkeys.exceptions
import
InvalidKeyException
from
sshpubkeys.exceptions
import
InvalidKeyException
public_key
=
self
.
cleaned_data
[
'public_key'
]
ssh
=
SSHKey
(
public_key
)
ssh
=
SSHKey
(
public_key
)
try
:
try
:
ssh
.
parse
()
ssh
.
parse
()
...
...
apps/users/models.py
View file @
8a5a4f33
...
@@ -80,6 +80,7 @@ class User(AbstractUser):
...
@@ -80,6 +80,7 @@ class User(AbstractUser):
date_expired
=
models
.
DateTimeField
(
default
=
date_expired_default
,
blank
=
True
,
null
=
True
,
date_expired
=
models
.
DateTimeField
(
default
=
date_expired_default
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Date expired'
))
verbose_name
=
_
(
'Date expired'
))
created_by
=
models
.
CharField
(
max_length
=
30
,
default
=
''
,
verbose_name
=
_
(
'Created by'
))
created_by
=
models
.
CharField
(
max_length
=
30
,
default
=
''
,
verbose_name
=
_
(
'Created by'
))
is_public_key_valid
=
models
.
BooleanField
(
default
=
False
)
@property
@property
def
password_raw
(
self
):
def
password_raw
(
self
):
...
...
apps/users/serializers.py
View file @
8a5a4f33
...
@@ -46,11 +46,18 @@ class UserPKUpdateSerializer(serializers.ModelSerializer):
...
@@ -46,11 +46,18 @@ class UserPKUpdateSerializer(serializers.ModelSerializer):
class
Meta
:
class
Meta
:
model
=
User
model
=
User
fields
=
[
'id'
,
'_private_key'
]
fields
=
[
'id'
,
'_public_key'
]
def
validate__private_key
(
self
,
value
):
def
validate__public_key
(
self
,
value
):
from
users.utils
import
validate_ssh_pk
from
sshpubkeys
import
SSHKey
checked
,
reason
=
validate_ssh_pk
(
value
)
from
sshpubkeys.exceptions
import
InvalidKeyException
if
not
checked
:
ssh
=
SSHKey
(
value
)
raise
serializers
.
ValidationError
(
_
(
'Not a valid ssh private key.'
))
try
:
ssh
.
parse
()
except
InvalidKeyException
as
e
:
print
e
raise
serializers
.
ValidationError
(
_
(
'Not a valid ssh public key'
))
except
NotImplementedError
as
e
:
print
e
raise
serializers
.
ValidationError
(
_
(
'Not a valid ssh public key'
))
return
value
return
value
apps/users/templates/users/_user_
reset
_pk_modal.html
→
apps/users/templates/users/_user_
update
_pk_modal.html
View file @
8a5a4f33
{% extends '_modal.html' %}
{% extends '_modal.html' %}
{% load i18n %}
{% load i18n %}
{% block modal_id %}user_
reset
_pk_modal{% endblock %}
{% block modal_id %}user_
update
_pk_modal{% endblock %}
{% block modal_title%}{% trans
'Reset User SSH Private Key'
%}{% endblock %}
{% block modal_title%}{% trans
"Update User SSH Public Key"
%}{% endblock %}
{% block modal_body %}
{% block modal_body %}
<textarea
id=
"txt_pk"
class=
"form-control"
cols=
"30"
rows=
"10"
placeholder=
"
-----BEGIN RSA PRIVATE KEY-----
"
></textarea>
<textarea
id=
"txt_pk"
class=
"form-control"
cols=
"30"
rows=
"10"
placeholder=
"
ssh-rsa AAAAB3NzaC1yc2EAA.....
"
></textarea>
{% endblock %}
{% endblock %}
{% block modal_confirm_id %}btn_user_
reset
_pk{% endblock %}
{% block modal_confirm_id %}btn_user_
update
_pk{% endblock %}
apps/users/templates/users/first_login.html
View file @
8a5a4f33
...
@@ -3,10 +3,12 @@
...
@@ -3,10 +3,12 @@
{% load i18n %}
{% load i18n %}
{% load bootstrap %}
{% load bootstrap %}
{% block custom_head_css_js %}
{% block custom_head_css_js %}
{{ wizard.form.media }}
{{ wizard.form.media }}
<link
href=
"{% static 'css/plugins/steps/jquery.steps.css' %}"
rel=
"stylesheet"
>
<link
href=
"{% static 'css/plugins/steps/jquery.steps.css' %}"
rel=
"stylesheet"
>
{% endblock %}
{% endblock %}
{% block first_login_message %}{% endblock %}
{% block content %}
{% block content %}
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
<div
class=
"row"
>
<div
class=
"row"
>
...
...
apps/users/templates/users/user_detail.html
View file @
8a5a4f33
...
@@ -160,6 +160,14 @@
...
@@ -160,6 +160,14 @@
</span>
</span>
</td>
</td>
</tr>
</tr>
<tr>
<td>
{% trans 'Update ssh key' %}:
</td>
<td>
<span
class=
"pull-right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
id=
"btn_update_pk"
style=
"width: 54px;"
data-toggle=
"modal"
data-target=
"#user_update_pk_modal"
>
{% trans 'Update' %}
</button>
</span>
</td>
</tr>
</tbody>
</tbody>
</table>
</table>
</div>
</div>
...
@@ -207,6 +215,7 @@
...
@@ -207,6 +215,7 @@
</div>
</div>
</div>
</div>
</div>
</div>
{% include 'users/_user_update_pk_modal.html' %}
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{% block custom_foot_js %}
<script>
<script>
...
@@ -352,6 +361,33 @@ $(document).ready(function() {
...
@@ -352,6 +361,33 @@ $(document).ready(function() {
},
function
()
{
},
function
()
{
doReset
();
doReset
();
});
});
}).
on
(
'click'
,
'#btn_user_update_pk'
,
function
(){
var
$this
=
$
(
this
);
var
pk
=
$
(
'#txt_pk'
).
val
();
var
the_url
=
'{% url "users:user-update-pk-api" pk=user_object.id %}'
;
var
body
=
{
'_public_key'
:
pk
};
var
success
=
function
()
{
$
(
'#txt_pk'
).
val
(
''
);
$this
.
closest
(
'.modal'
).
modal
(
'hide'
);
var
msg
=
"{% trans 'Successfully updated the SSH public key.' %}"
;
swal
(
"{% trans 'User SSH Public Key Update' %}"
,
msg
,
"success"
);
};
var
fail
=
function
()
{
var
msg
=
"{% trans 'Failed to update the user
\
's SSH public key.' %}"
;
swal
({
title
:
"{% trans 'User SSH Public Key Update' %}"
,
text
:
msg
,
type
:
"error"
,
showCancelButton
:
false
,
confirmButtonColor
:
"#DD6B55"
,
confirmButtonText
:
"{% trans 'Confirm' %}"
,
closeOnConfirm
:
true
},
function
()
{
$
(
'#txt_pk'
).
focus
();
}
);
}
APIUpdateAttr
({
url
:
the_url
,
body
:
JSON
.
stringify
(
body
),
success
:
success
,
error
:
fail
});
});
});
</script>
</script>
{% endblock %}
{% endblock %}
apps/users/urls.py
View file @
8a5a4f33
...
@@ -43,6 +43,7 @@ urlpatterns += [
...
@@ -43,6 +43,7 @@ urlpatterns += [
api
.
UserAttributeApi
.
as_view
(),
name
=
'user-patch-api'
),
api
.
UserAttributeApi
.
as_view
(),
name
=
'user-patch-api'
),
url
(
r'^v1/users/(?P<pk>\d+)/reset-password/$'
,
api
.
UserResetPasswordApi
.
as_view
(),
name
=
'user-reset-password-api'
),
url
(
r'^v1/users/(?P<pk>\d+)/reset-password/$'
,
api
.
UserResetPasswordApi
.
as_view
(),
name
=
'user-reset-password-api'
),
url
(
r'^v1/users/(?P<pk>\d+)/reset-pk/$'
,
api
.
UserResetPKApi
.
as_view
(),
name
=
'user-reset-pk-api'
),
url
(
r'^v1/users/(?P<pk>\d+)/reset-pk/$'
,
api
.
UserResetPKApi
.
as_view
(),
name
=
'user-reset-pk-api'
),
url
(
r'^v1/users/(?P<pk>\d+)/update-pk/$'
,
api
.
UserUpdatePKApi
.
as_view
(),
name
=
'user-update-pk-api'
),
url
(
r'^v1/user-groups$'
,
api
.
UserGroupListAddApi
.
as_view
(),
name
=
'user-group-list-api'
),
url
(
r'^v1/user-groups$'
,
api
.
UserGroupListAddApi
.
as_view
(),
name
=
'user-group-list-api'
),
url
(
r'^v1/user-groups/(?P<pk>[0-9]+)$'
,
url
(
r'^v1/user-groups/(?P<pk>[0-9]+)$'
,
api
.
UserGroupDetailDeleteUpdateApi
.
as_view
(),
name
=
'user-group-detail-api'
),
api
.
UserGroupDetailDeleteUpdateApi
.
as_view
(),
name
=
'user-group-detail-api'
),
...
...
apps/users/views.py
View file @
8a5a4f33
...
@@ -19,7 +19,7 @@ from django.views.decorators.debug import sensitive_post_parameters
...
@@ -19,7 +19,7 @@ from django.views.decorators.debug import sensitive_post_parameters
from
django.views.generic.base
import
TemplateView
from
django.views.generic.base
import
TemplateView
from
django.views.generic.list
import
ListView
from
django.views.generic.list
import
ListView
from
django.views.generic.edit
import
CreateView
,
DeleteView
,
UpdateView
,
FormView
,
SingleObjectMixin
,
\
from
django.views.generic.edit
import
CreateView
,
DeleteView
,
UpdateView
,
FormView
,
SingleObjectMixin
,
\
FormMixin
,
ModelFormMixin
,
ProcessFormView
,
BaseCreateView
FormMixin
from
django.views.generic.detail
import
DetailView
from
django.views.generic.detail
import
DetailView
from
formtools.wizard.views
import
SessionWizardView
from
formtools.wizard.views
import
SessionWizardView
...
@@ -332,6 +332,7 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
...
@@ -332,6 +332,7 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
if
field
.
name
==
'enable_otp'
:
if
field
.
name
==
'enable_otp'
:
user
.
enable_otp
=
field
.
value
()
user
.
enable_otp
=
field
.
value
()
user
.
is_first_login
=
False
user
.
is_first_login
=
False
user
.
is_public_key_valid
=
True
user
.
save
()
user
.
save
()
return
redirect
(
reverse
(
'index'
))
return
redirect
(
reverse
(
'index'
))
...
@@ -351,6 +352,16 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
...
@@ -351,6 +352,16 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
}
}
return
super
(
UserFirstLoginView
,
self
)
.
get_form_initial
(
step
)
return
super
(
UserFirstLoginView
,
self
)
.
get_form_initial
(
step
)
def
get_form
(
self
,
step
=
None
,
data
=
None
,
files
=
None
):
form
=
super
(
UserFirstLoginView
,
self
)
.
get_form
(
step
,
data
,
files
)
if
step
is
None
:
step
=
self
.
steps
.
current
if
step
==
'1'
:
form
.
user
=
self
.
request
.
user
return
form
class
UserAssetPermissionView
(
AdminUserRequiredMixin
,
FormMixin
,
SingleObjectMixin
,
ListView
):
class
UserAssetPermissionView
(
AdminUserRequiredMixin
,
FormMixin
,
SingleObjectMixin
,
ListView
):
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
...
@@ -376,7 +387,7 @@ class UserAssetPermissionView(AdminUserRequiredMixin, FormMixin, SingleObjectMix
...
@@ -376,7 +387,7 @@ class UserAssetPermissionView(AdminUserRequiredMixin, FormMixin, SingleObjectMix
def
get_queryset
(
self
):
def
get_queryset
(
self
):
asset_permissions
=
set
(
self
.
object
.
asset_permissions
.
all
())
\
asset_permissions
=
set
(
self
.
object
.
asset_permissions
.
all
())
\
|
self
.
get_asset_permission_inherit_from_user_group
()
|
self
.
get_asset_permission_inherit_from_user_group
()
return
list
(
asset_permissions
)
return
list
(
asset_permissions
)
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
...
...
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