kopia lustrzana https://github.com/OpenDroneMap/WebODM
Add /api/users
rodzic
2beaad3910
commit
0db85bba66
|
@ -70,9 +70,9 @@ class ProjectViewSet(viewsets.ModelViewSet):
|
|||
|
||||
result = []
|
||||
|
||||
perms = get_users_with_perms(project, attach_perms=True)
|
||||
perms = get_users_with_perms(project, attach_perms=True, with_group_users=False)
|
||||
for user in perms:
|
||||
result.append({'user': user.username,
|
||||
result.append({'username': user.username,
|
||||
'owner': project.owner == user,
|
||||
'permissions': normalized_perm_names(perms[user])})
|
||||
|
||||
|
|
|
@ -12,12 +12,16 @@ from rest_framework_jwt.views import obtain_jwt_token
|
|||
from .tiler import TileJson, Bounds, Metadata, Tiles, Export
|
||||
from .potree import Scene, CameraView
|
||||
from .workers import CheckTask, GetTaskResult
|
||||
from .users import UserViewSet
|
||||
from webodm import settings
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register(r'projects', ProjectViewSet)
|
||||
router.register(r'processingnodes', ProcessingNodeViewSet)
|
||||
router.register(r'presets', PresetViewSet, base_name='presets')
|
||||
|
||||
if settings.ENABLE_USERS_API:
|
||||
router.register(r'users', UserViewSet, base_name='users')
|
||||
|
||||
tasks_router = routers.NestedSimpleRouter(router, r'projects', lookup='project')
|
||||
tasks_router.register(r'tasks', TaskViewSet, base_name='projects-tasks')
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
from django.contrib.auth.models import User
|
||||
from rest_framework import serializers, viewsets, mixins, status, exceptions, permissions
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['username', 'email']
|
||||
|
||||
class UserViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
||||
serializer_class = UserSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
# Disable pagination when not requesting any page
|
||||
def paginate_queryset(self, queryset):
|
||||
if self.paginator and self.request.query_params.get(self.paginator.page_query_param, None) is None:
|
||||
return None
|
||||
return super().paginate_queryset(queryset)
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = User.objects.all()
|
||||
|
||||
search = self.request.query_params.get('search', None)
|
||||
if search is not None:
|
||||
queryset = queryset.filter(username__istartswith=search) | queryset.filter(email__istartswith=search)
|
||||
|
||||
limit = self.request.query_params.get('limit', None)
|
||||
if limit is not None:
|
||||
try:
|
||||
queryset = queryset[:abs(int(limit))]
|
||||
except ValueError:
|
||||
raise exceptions.ValidationError(detail="Invalid query parameters")
|
||||
|
||||
return queryset
|
|
@ -25,7 +25,8 @@ class EditPermissionsPanel extends React.Component {
|
|||
error: "",
|
||||
loading: false,
|
||||
permissions: [],
|
||||
validUsernames: []
|
||||
validUsernames: {},
|
||||
validatingUser: false
|
||||
};
|
||||
|
||||
this.backgroundFailedColor = Css.getValue('btn-danger', 'backgroundColor');
|
||||
|
@ -36,7 +37,8 @@ class EditPermissionsPanel extends React.Component {
|
|||
|
||||
this.permsRequest =
|
||||
$.getJSON(`/api/projects/${this.props.projectId}/permissions/`, json => {
|
||||
let validUsernames = json.map(p => p.user);
|
||||
let validUsernames = {};
|
||||
json.forEach(p => validUsernames[p.username] = true);
|
||||
this.setState({validUsernames, permissions: json});
|
||||
})
|
||||
.fail(() => {
|
||||
|
@ -47,12 +49,43 @@ class EditPermissionsPanel extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
validateUsername = (username) => {
|
||||
if (this.validateReq){
|
||||
this.validateReq.abort();
|
||||
this.validateReq = null;
|
||||
}
|
||||
|
||||
if (this.validateTimeout){
|
||||
clearTimeout(this.validateTimeout);
|
||||
this.validateTimeout = null;
|
||||
}
|
||||
|
||||
this.setState({validatingUser: true});
|
||||
|
||||
this.validateTimeout = setTimeout(() => {
|
||||
this.validateReq = $.getJSON(`/api/users/?limit=30&search=${encodeURIComponent(username)}`)
|
||||
.done((json) => {
|
||||
json.forEach(u => {
|
||||
this.state.validUsernames[u.username] = true;
|
||||
});
|
||||
|
||||
this.setState({validUsernames: this.state.validUsernames});
|
||||
}).fail(() => {
|
||||
|
||||
}).always(() => {
|
||||
this.setState({validatingUser: false});
|
||||
});
|
||||
}, 300);
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
if (!this.props.lazyLoad) this.loadPermissions();
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
if (this.permsRequest) this.permsRequest.abort();
|
||||
if (this.validateReq) this.validateReq.abort();
|
||||
if (this.validateTimeout) clearTimeout(this.validateTimeout);
|
||||
}
|
||||
|
||||
handleChangePermissionRole = e => {
|
||||
|
@ -61,7 +94,9 @@ class EditPermissionsPanel extends React.Component {
|
|||
|
||||
handleChangePermissionUser = perm => {
|
||||
return e => {
|
||||
perm.user = e.target.value;
|
||||
perm.username = e.target.value;
|
||||
|
||||
this.validateUsername(perm.username);
|
||||
|
||||
// Update
|
||||
this.setState({permissions: this.state.permissions});
|
||||
|
@ -87,13 +122,13 @@ class EditPermissionsPanel extends React.Component {
|
|||
}
|
||||
|
||||
getColorFor = (username) => {
|
||||
if (this.state.validUsernames.indexOf(username) !== -1) return "";
|
||||
if (this.state.validatingUser || this.state.validUsernames[username]) return "";
|
||||
else return this.backgroundFailedColor;
|
||||
}
|
||||
|
||||
addNewPermission = () => {
|
||||
this.setState(update(this.state, {
|
||||
permissions: {$push: [{user: "", permissions: ["view"]}]}
|
||||
permissions: {$push: [{username: "", permissions: ["view"]}]}
|
||||
}));
|
||||
|
||||
setTimeout(() => {
|
||||
|
@ -110,18 +145,19 @@ class EditPermissionsPanel extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const permissions = this.state.permissions.map((p, i) => <div key={i}>
|
||||
const permissions = this.state.permissions.map((p, i) => <form autoComplete="off" key={i}>
|
||||
<div className="permission">
|
||||
<div className="username-container">
|
||||
<i className="fa fa-user user-indicator"/>
|
||||
<input
|
||||
style={{color: this.getColorFor(p.user)}}
|
||||
style={{color: this.getColorFor(p.username)}}
|
||||
onChange={this.handleChangePermissionUser(p)}
|
||||
type="text"
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
disabled={p.owner}
|
||||
value={p.user}
|
||||
value={p.username}
|
||||
className="form-control username"
|
||||
placeholder={_("Username / e-mail")}
|
||||
placeholder={_("Username")}
|
||||
ref={(domNode) => this.lastTextbox = domNode} />
|
||||
</div>
|
||||
<div className="remove">
|
||||
|
@ -133,7 +169,7 @@ class EditPermissionsPanel extends React.Component {
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>);
|
||||
</form>);
|
||||
|
||||
return (
|
||||
<div className="edit-permissions-panel">
|
||||
|
|
|
@ -69,6 +69,12 @@ SINGLE_USER_MODE = False
|
|||
# URL to redirect to if there are no processing nodes when visiting the dashboard
|
||||
PROCESSING_NODES_ONBOARDING = None
|
||||
|
||||
# Enable the /api/users endpoint which is used for autocompleting
|
||||
# usernames when handling project permissions. This can be disabled
|
||||
# for security reasons if you don't want to let authenticated users
|
||||
# retrieve the user list.
|
||||
ENABLE_USERS_API = True
|
||||
|
||||
# Enable desktop mode. In desktop mode some styling changes
|
||||
# are applied to make the application look nicer on desktop
|
||||
# as well as disabling certain features (e.g. sharing)
|
||||
|
|
Ładowanie…
Reference in New Issue