def widget_detail(request, id, offset=0): wc = get_object_or_404(WidgetConfig, id=int(id)) if not check_user_superuser(request.user) and \ wc.group and not (check_ug_membership(request.user, wc.group) or \ wc.group.public or wc.type == WidgetConfig.TYPE_MICROSITE) or \ wc.user and wc.user_id != request.user.pk: return HttpResponseForbidden('Access denied!') widget_class = widget_registry.get(wc.app_name, wc.widget_name) if widget_class is None: return render('cosinnus/widgets/not_found.html') widget = widget_class(request, wc) widget_content, rows_returned, has_more = widget.get_data(int(offset)) data = { 'X-Cosinnus-Widget-Content': widget_content, 'X-Cosinnus-Widget-Title': force_text(widget.title), 'X-Cosinnus-Widget-App-Name': force_text(wc.app_name), 'X-Cosinnus-Widget-Widget-Name': force_text(wc.widget_name), 'X-Cosinnus-Widget-Num-Rows-Returned': rows_returned, 'X-Cosinnus-Widget-Has-More-Data': 'true' if has_more else 'false', } title_url = widget.title_url if title_url is not None: data['X-Cosinnus-Widget-Title-URL'] = force_text(title_url) return JSONResponse(data)
def get_response(self): data = { 'group': self.group.name, 'fields': self.fields, 'rows': self.get_rows(), } return JSONResponse(data)
def get(self, request, *args, **kwargs): if self.is_ajax_request_url: # Prevent access to ajaxible paths from non-ajax requests if not request.is_ajax(): return HttpResponseBadRequest( "API calls do not supported direct access.") response = super(BaseAjaxableResponseMixin, self).get(request, *args, **kwargs) if not self.serializer_class: raise ImproperlyConfigured( 'Missing property serialzer_class for object "%s" ' '(needed by Ajax Mixins)' % self.__class__.__name__) context = {'request': self.request} serializer = self.serializer_class(self.get_serializable_content(), many=self.is_object_collection, context=context) return JSONResponse(serializer.data, status=response.status_code) else: return super(BaseAjaxableResponseMixin, self).get(request, *args, **kwargs) def get_serializable_content(self): raise NotImplementedError("Subclasses must implement this method")
def login_api(request, authentication_form=AuthenticationForm): """ Logs the user specified by the `authentication_form` in. """ if request.method == "POST": request = patch_body_json_data(request) # TODO: Django<=1.5: Django 1.6 removed the cookie check in favor of CSRF request.session.set_test_cookie() form = authentication_form(request, data=request.POST) if form.is_valid(): auth_login(request, form.get_user()) return JSONResponse({}) else: return JSONResponse(form.errors, status=401) else: return JSONResponse({}, status=405) # Method not allowed
def entry_toggle_complete_me_view_api(request, pk, group): """ Logs the user specified by the `authentication_form` in. """ if request.method == "POST": # TODO: Django<=1.5: Django 1.6 removed the cookie check in favor of CSRF request.session.set_test_cookie() pk = request.POST.get('pk') is_completed = request.POST.get('is_completed') instance = get_object_or_404(TodoEntry, pk=pk) if not check_object_write_access(instance, request.user): return JSONResponse( 'You do not have the necessary permissions to modify this object!', status=403) if is_completed == "true": instance.completed_by = request.user instance.completed_date = now() if instance.completed_by != instance.creator: sender = instance sender.request = request cosinnus_notifications.user_completed_my_todo.send( sender=sender, user=instance.completed_by, obj=instance, audience=[instance.creator]) else: instance.completed_by = None instance.completed_date = None instance.save() return JSONResponse({ 'status': 'success', 'is_completed': instance.is_completed })
def widget_add_group(request, group, app_name, widget_name): widget_class = widget_registry.get(app_name, widget_name) form_class = widget_class.get_setup_form_class() if request.method == "POST": form = form_class(request.POST) if form.is_valid(): widget = widget_class.create(request, group=group) widget.save_config(form.cleaned_data) return JSONResponse({'id': widget.id}) else: form = form_class() d = { 'form': form, 'submit_label': _('Add widget'), } c = RequestContext(request) return render_to_response('cosinnus/widgets/setup.html', d, c)
def widget_detail(request, id): wc = get_object_or_404(WidgetConfig, id=int(id)) if wc.group and not (check_ug_membership(request.user, wc.group) or wc.group.public) or \ wc.user and wc.user_id != request.user.pk: return HttpResponseForbidden('Access denied!') widget_class = widget_registry.get(wc.app_name, wc.widget_name) widget = widget_class(request, wc) data = widget.get_data() if isinstance(data, six.string_types): resp = HttpResponse(data) else: resp = JSONResponse(data) resp['X-Cosinnus-Widget-Title'] = force_text(widget.title) if widget.title_url is not None: resp['X-Cosinnus-Widget-Title-URL'] = force_text(widget.title_url) resp['X-Cosinnus-Widget-App-Name'] = force_text(wc.app_name) resp['X-Cosinnus-Widget-Widget-Name'] = force_text(wc.widget_name) return resp
def widget_edit(request, id): wc = get_object_or_404(WidgetConfig, id=int(id)) if wc.group and not check_ug_admin(request.user, wc.group) or \ wc.user and wc.user_id != request.user.pk: return HttpResponseForbidden('Access denied!') widget_class = widget_registry.get(wc.app_name, wc.widget_name) form_class = widget_class.get_setup_form_class() widget = widget_class(request, wc) if request.method == "POST": form = form_class(request.POST) if form.is_valid(): widget.save_config(form.cleaned_data) return JSONResponse({'id': widget.id}) else: form = form_class(initial=dict(widget.config)) d = { 'form': form, 'submit_label': _('Change'), } c = RequestContext(request) return render_to_response('cosinnus/widgets/setup.html', d, c)
def logout_integrated(request): """ Logs an integrated user out by setting a force-logout flag on him. """ if request.method == "POST": username = request.POST.get('username', None) password = request.POST.get('password', None) if not username or not password: return HttpResponseBadRequest('Missing POST parameters!') user = _get_integrated_user_validated(username, password) request.user = user # set the user to be logged out on next request user.cosinnus_profile.settings['force_logout_next_request'] = True user.cosinnus_profile.save() return JSONResponse({}) else: raise Http404
def report_object(request): if not request.is_ajax() or not request.method == 'POST': return HttpResponseNotAllowed(['POST']) if not request.user.is_authenticated: return HttpResponseForbidden('Not authenticated.') cls = request.POST.get('cls', None) # expects 'cosinnus_note.Note' obj_id = request.POST.get('id', None) text = request.POST.get('text', None) if not cls and obj_id and text: raise ValueError('Incomplete data submitted.') app_label, model = cls.split('.') if model.lower() == 'user': model_cls = get_user_model() else: model_cls = apps.get_model(app_label, model) content_type = ContentType.objects.get_for_model(model_cls) report_obj = CosinnusReportedObject.objects.create( content_type=content_type, object_id=obj_id, text=text, creator=request.user) # TODO: notification to portal admins _notify_users_for_reported_objects(report_obj, request) """ data = { 'status': 'error', } """ data = { 'status': 'success', } return JSONResponse(data, safe=False)
def widget_list(request): data = {} for app, widgets in widget_registry: data[app] = tuple(widgets) return JSONResponse(data)
def test_status_code(self): r = JSONResponse({'key': "val"}, status=404) self.assertEqual(r.content, b'{"key": "val"}') self.assertEqual(r.status_code, 404) self.assertEqual(r['content-type'], self.content_type)
def test_datetime(self): r = JSONResponse( {'datetime': datetime.datetime(2014, 3, 4, 12, 34, 56)}) self.assertEqual(r.content, b'{"datetime": "2014-03-04T12:34:56"}') self.assertEqual(r.status_code, 200) self.assertEqual(r['content-type'], self.content_type)
def test_float(self): r = JSONResponse({'float': 1.23}) self.assertEqual(r.content, b'{"float": 1.23}') self.assertEqual(r.status_code, 200) self.assertEqual(r['content-type'], self.content_type)
def test_number(self): r = JSONResponse({'num': 1}) self.assertEqual(r.content, b'{"num": 1}') self.assertEqual(r.status_code, 200) self.assertEqual(r['content-type'], self.content_type)
def test_empty(self): r = JSONResponse({}) self.assertEqual(r.content, b'{}') self.assertEqual(r.status_code, 200) self.assertEqual(r['content-type'], self.content_type)
def render_to_json_response(self, context, **response_kwargs): if self.is_ajax_request_url: return JSONResponse(context, **response_kwargs) else: return HttpResponseBadRequest()
def create_user_integrated(request): if request.method == "POST": # spam protection # TODO: FIXME: not working right now, because of different session keys for each ajax cross-site POST :/ session_key = request.session._get_or_create_session_key() if cache.get(CREATE_INTEGRATED_USER_SESSION_CACHE_KEY % session_key): return HttpResponseBadRequest( 'You have been doing this too often. Slow down!') user_email = request.POST.get('user_email', None) existing_username = request.POST.get('existing_username', None) # this is actually the hashed password of the remote user user_password = request.POST.get('user_password', None) if not user_email or not user_password: return HttpResponseBadRequest('Missing POST parameters!') first_name = request.POST.get('first_name', '') last_name = request.POST.get('last_name', '') # handshake on the integrating server, url from settings, NEVER FROM REQUEST! handshake_url = getattr(settings, 'COSINNUS_INTEGRATED_PORTAL_HANDSHAKE_URL', None) if not handshake_url: raise ImproperlyConfigured( 'Cannot create integrated user: COSINNUS_INTEGRATED_PORTAL_HANDSHAKE_URL is not configured in settings!' ) data = { 'user_email': user_email, } logger.warn('Sending handshake request.', extra={ 'data': data, 'url': handshake_url }) req = requests.post(handshake_url, data=data, verify=False) logger.warn('Handshake request returned.', extra={ 'status': req.status_code, 'content': req._content }) if not req.status_code == 200: logger.error( 'Failed to send handshake! Have you configured the correct COSINNUS_INTEGRATED_PORTAL_HANDSHAKE_URL?', extra={ 'returned_request': req, 'handshake_url': handshake_url, 'content': req._content }) return HttpResponseBadRequest( 'Could not create integrated user: Handshake could not be established! Code: %d' % req.status_code) response = req.json() if not response['status'] == 'ok': return HttpResponseBadRequest( 'Could not create integrated user: Handshake failed!') # handshake succeeded, either create new user or connect to existing one user = None if existing_username: try: user = USER_MODEL.objects.get(username=existing_username) # we had already connected to a useraccount, so take this one # (the external mail might be different, so do not try to match over that, # as it would switch the user on the cosinnus side!) except USER_MODEL.DoesNotExist: logger.error( 'Cosinnus integration tried to retrieve a previously connected user, but user with username "%s" could not be found! Aborting user integration!' % existing_username) return HttpResponseBadRequest( 'Cosinnus integration tried to retrieve a previously connected user, but user with username "%s" could not be found! Aborting user integration!' % existing_username) if not user: try: user = USER_MODEL.objects.get(email=user_email) # user already exists for this email, but wasn't connected # since we trust both servers, we connect the existing user account except USER_MODEL.DoesNotExist: user = None logger.warn('Finding existing user.', extra={'user': user}) # create new user if not existed if user is None: password = '******' data = { 'username': user_email, 'email': user_email, 'password1': password, 'password2': password, 'first_name': first_name, 'last_name': last_name, 'tos_check': True, } # use Cosinnus' UserCreationForm to apply all usual user-creation-related effects form = UserCreationForm(data) if form.is_valid(): user = form.save() else: logger.warn('User form invalid.', extra={'errors': force_text(form.errors)}) return JSONResponse(data={ 'status': 'fail', 'reason': force_text(form.errors) }) get_user_profile_model()._default_manager.get_for_user(user) # set the new user's password's hash to that of the connected user. user.password = user_password user.save() logger.warn('Cosinnus integration: User saved.', extra={'user': user}) else: # user existed before, update first_name, last_name. # NEVER update the password to prevent account hijacking through a faked email! user.first_name = first_name user.last_name = last_name user.save() logger.warn('Cosinnus integration: User names updated.', extra={'user': user}) # if we got an avatar sent with the request, always update/save it to the new user's profile if request.FILES and 'avatar' in request.FILES: user.cosinnus_profile.avatar = request.FILES.get('avatar') logger.warn('Cosinnus integration: Avatar saved/updated.', extra={'user': user}) # always accept terms of service automatically in integrated portals accept_user_tos_for_portal(user) # retransmit a hashed version of the hashed password. # yes, we double hash the original password. because then the first password hash # is only exposed once, during user creation, and never again after that. # all that is exposed to the client afterwards is a double hash, making this a bit cleaner. remote_password = IntegratedHasher.encode(user.password, salt) # set session key into cache cache.set(CREATE_INTEGRATED_USER_SESSION_CACHE_KEY % session_key, 'True', settings.COSINNUS_INTEGRATED_CREATE_USER_CACHE_TIMEOUT) logger.warn('User creation success, returning ok', extra={'username': user.username}) return JSONResponse( data={ 'status': 'ok', 'remote_username': user.username, 'remote_password': remote_password }) else: raise Http404
def file_upload_inline(request, group): """ Inline file upload to be called from jQuery FileUpload. @param request.on_success: Determines what kind of data will be sent back, and in cosinnus.JS, determines what will be done with the data. Options: - 'add_to_select2' (default): Will render a select2 pill and in JS, append it to the attach-file select2 field. - 'refresh_page' will add a message to the request and in JS refresh the browser page - 'render_object' will render the single file template(s) and in JS append them to the file list """ if not request.is_ajax() or not request.method=='POST': return HttpResponseNotAllowed(['POST']) on_success = request.POST.get('on_success', 'add_to_select2') direct_upload = request.POST.get('direct_upload', False) make_private = request.POST.get('private_upload', False) # resolve group either from the slug, or like the permission group mixin does ist # (group type needs to also be used for that= group = get_group_for_request(group, request) if not group: logger.error('No group found when trying to upload a file!', extra={'group_slug': group, 'request': request, 'path': request.path}) return JSONResponse({'status': 'error', 'message': _('Internal Error: Group not Found')}) # do permission checking using has_write_access(request.user, group) if not check_group_create_objects_access(group, request.user): logger.error('Permission error while uploading an attached file directly!', extra={'user': request.user, 'request': request, 'path': request.path, 'group_slug': group}) return JSONResponse({'status': 'error', 'message': _('Permission for upload denied')}) # add any other required kwargs (group) and stuff correctly so the form can be saved post = request.POST post._mutable = True post.update({ 'group_id': group.id }) base_upload_folder = None upload_to_attachment_folder = False if 'target_folder' in post: base_upload_folder = get_object_or_404(FileEntry, id=int(post.get('target_folder'))) if not base_upload_folder: # check if the group has a folder with slug 'uploads' and if not, create one base_upload_folder = get_or_create_attachment_folder(group) upload_to_attachment_folder = True file_info_array = json.loads(post.get('file_info', '[]')) result_list = [] for file_index, dict_file in enumerate(request.FILES.getlist('file')): upload_folder = None # unless we are uploading as attachment, see if we have any further folder info for this file if not upload_to_attachment_folder and len(file_info_array) > file_index: # get relative path for the ith file, it should be the same as in the FILES list relative_path = file_info_array[file_index]['relative_path'] name = file_info_array[file_index]['name'] if relative_path: # sanity check, file name in file info must match FILES file name if not name == dict_file._name: logger.warn('File upload sanity check failed: File order of file with relative path info and FILES list did not match! (Upload may have sorted the user\'s file in the wrong folder)', extra={ 'file_info': file_info_array, 'FILES_list': request.FILES.getlist('file')}) upload_folder = _create_folders_for_path_string(base_upload_folder, relative_path) # switch mode to refresh page if we had at least one folder upload on_success = 'refresh_page' if not upload_folder: upload_folder = base_upload_folder single_file_dict = MultiValueDict({'file': [dict_file]}) post.update({ 'title': clean_single_line_text(dict_file._name), }) form = FileForm(post, single_file_dict, group=group, initial={}) if form.is_valid(): # form.instance is the FileEntry, not the media tag form.instance.group = group form.instance.creator = request.user form.instance.path = upload_folder.path form.instance._filesize = form.instance.file.file.size if not direct_upload: form.instance.no_notification = True # disable notifications on non-direct (attached, etc) uploads saved_file = form.save() # flag for uploading the file visible only to oneself, as used in message attachments if make_private: saved_file.media_tag.visibility = BaseTagObject.VISIBILITY_USER saved_file.media_tag.save() # render either for the file list or for the attached objects if on_success == 'render_object': context = { 'file': saved_file, 'do_highlight': True } result_list.append(render_to_string('cosinnus_file/single_file_detailed.html', context, request)) else: # pipe the file into the select2 JSON representation to be displayed as select2 pill pill_id, pill_html = build_attachment_field_result('cosinnus_file.FileEntry', saved_file) result_list.append({'text': pill_html, 'id': pill_id}) else: logger.warn('Form error while uploading an attached file directly!', extra={'form.errors': form.errors, 'user': request.user, 'request': request, 'path': request.path, 'group_slug': group}) message = _('The uploaded file was invalid.') if form.forms['obj'].errors.get('file', None): message = form.forms['obj'].errors.get('file', None) return JSONResponse({'status': 'error', 'message': message}) if result_list: if on_success == 'refresh_page': messages.success(request, ungettext('%(count)d File was added successfully.', '%(count)d Files were added successfully.', len(result_list)) % {'count': len(result_list)}) return JSONResponse({'status': 'ok', 'on_success': on_success, 'data': result_list}) else: return JSONResponse({'status': 'error', 'message': _('The file you uploaded was too large or the file type was not permitted to be uploaded!')})
def logout_api(request): """ Logs the user out. """ auth_logout(request) return JSONResponse({})