Example #1
0
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)
Example #2
0
 def get_response(self):
     data = {
         'group': self.group.name,
         'fields': self.fields,
         'rows': self.get_rows(),
     }
     return JSONResponse(data)
Example #3
0
    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")
Example #4
0
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
Example #5
0
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
        })
Example #6
0
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)
Example #7
0
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
Example #8
0
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)
Example #9
0
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
Example #10
0
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)
Example #11
0
def widget_list(request):
    data = {}
    for app, widgets in widget_registry:
        data[app] = tuple(widgets)
    return JSONResponse(data)
Example #12
0
 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)
Example #13
0
 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)
Example #14
0
 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)
Example #15
0
 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)
Example #16
0
 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)
Example #17
0
 def render_to_json_response(self, context, **response_kwargs):
     if self.is_ajax_request_url:
         return JSONResponse(context, **response_kwargs)
     else:
         return HttpResponseBadRequest()
Example #18
0
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
Example #19
0
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!')})
Example #20
0
def logout_api(request):
    """
    Logs the user out.
    """
    auth_logout(request)
    return JSONResponse({})