Ejemplo n.º 1
0
def _pages_from_json(request, offering, data):
    with django.db.transaction.atomic():
        try:
            data = data.decode('utf-8-sig')
        except UnicodeDecodeError:
            raise ValidationError(u"Bad UTF-8 data in file.")

        try:
            data = json.loads(data)
        except ValueError as e:
            raise ValidationError(u'JSON decoding error.  Exception was: "' +
                                  str(e) + '"')

        if not isinstance(data, dict):
            raise ValidationError(
                u'Outer JSON data structure must be an object.')
        if 'userid' not in data or 'token' not in data:
            raise ValidationError(
                u'Outer JSON data object must contain keys "userid" and "token".'
            )
        if 'pages' not in data:
            raise ValidationError(
                u'Outer JSON data object must contain keys "pages".')
        if not isinstance(data['pages'], list):
            raise ValidationError(u'Value for "pages" must be a list.')

        try:
            user = Person.objects.get(userid=data['userid'])
            member = Member.objects.exclude(role='DROP').get(person=user,
                                                             offering=offering)
        except Person.DoesNotExist, Member.DoesNotExist:
            raise ValidationError(u'Person with that userid does not exist.')

        if 'pages-token' not in user.config or user.config[
                'pages-token'] != data['token']:
            e = ValidationError(u'Could not validate authentication token.')
            e.status = 403
            raise e

        # if we get this far, the user is authenticated and we can start processing the pages...

        for i, pdata in enumerate(data['pages']):
            if not isinstance(pdata, dict):
                raise ValidationError(
                    u'Page #%i entry structure must be an object.' % (i))
            if 'label' not in pdata:
                raise ValidationError(
                    u'Page #%i entry does not have a "label".' % (i))

            # handle changes to the Page object
            pages = Page.objects.filter(offering=offering,
                                        label=pdata['label'])
            if pages:
                page = pages[0]
                old_ver = page.current_version()
            else:
                page = Page(offering=offering, label=pdata['label'])
                old_ver = None

            # check write permissions

            # mock the request object enough to satisfy _check_allowed()
            class FakeRequest(object):
                def is_authenticated(self):
                    return True

            fake_request = FakeRequest()
            fake_request.user = FakeRequest()
            fake_request.user.username = user.userid

            if old_ver:
                m = _check_allowed(fake_request, offering, page.can_write,
                                   page.editdate())
            else:
                m = _check_allowed(fake_request, offering,
                                   offering.page_creators())
            if not m:
                raise ValidationError(u'You can\'t edit page #%i.' % (i))

            # handle Page attributes
            if 'can_read' in pdata:
                if type(pdata['can_read']
                        ) != unicode or pdata['can_read'] not in ACL_DESC:
                    raise ValidationError(
                        u'Page #%i "can_read" value must be one of %s.' %
                        (i, ','.join(ACL_DESC.keys())))

                page.can_read = pdata['can_read']

            if 'can_write' in pdata:
                if type(pdata['can_write']) != unicode or pdata[
                        'can_write'] not in WRITE_ACL_DESC:
                    raise ValidationError(
                        u'Page #%i "can_write" value must be one of %s.' %
                        (i, ','.join(WRITE_ACL_DESC.keys())))
                if m.role == 'STUD':
                    raise ValidationError(
                        u'Page #%i: students can\'t change can_write value.' %
                        (i))
                page.can_write = pdata['can_write']

            if 'new_label' in pdata:
                if type(pdata['new_label']) != unicode:
                    raise ValidationError(
                        u'Page #%i "new_label" value must be a string.' % (i))
                if m.role == 'STUD':
                    raise ValidationError(
                        u'Page #%i: students can\'t change label value.' % (i))
                if Page.objects.filter(offering=offering,
                                       label=pdata['new_label']):
                    raise ValidationError(
                        u'Page #%i: there is already a page with that "new_label".'
                        % (i))

                page.label = pdata['new_label']

            page.save()

            # handle PageVersion changes
            ver = PageVersion(page=page, editor=member)

            if 'title' in pdata:
                if type(pdata['title']) != unicode:
                    raise ValidationError(
                        u'Page #%i "title" value must be a string.' % (i))

                ver.title = pdata['title']
            elif old_ver:
                ver.title = old_ver.title
            else:
                raise ValidationError(
                    u'Page #%i has no "title" for new page.' % (i))

            if 'comment' in pdata:
                if type(pdata['comment']) != unicode:
                    raise ValidationError(
                        u'Page #%i "comment" value must be a string.' % (i))

                ver.comment = pdata['comment']

            if 'use_math' in pdata:
                if type(pdata['use_math']) != bool:
                    raise ValidationError(
                        u'Page #%i "comment" value must be a boolean.' % (i))

                ver.set_math(pdata['use_math'])

            if 'wikitext-base64' in pdata:
                if type(pdata['wikitext-base64']) != unicode:
                    raise ValidationError(
                        u'Page #%i "wikitext-base64" value must be a string.' %
                        (i))
                try:
                    wikitext = base64.b64decode(pdata['wikitext-base64'])
                except TypeError:
                    raise ValidationError(
                        u'Page #%i "wikitext-base64" contains bad base BASE64 data.'
                        % (i))

                ver.wikitext = wikitext
            elif 'wikitext' in pdata:
                if type(pdata['wikitext']) != unicode:
                    raise ValidationError(
                        u'Page #%i "wikitext" value must be a string.' % (i))

                ver.wikitext = pdata['wikitext']
            elif old_ver:
                ver.wikitext = old_ver.wikitext
            else:
                raise ValidationError(
                    u'Page #%i has no wikitext for new page.' % (i))

            ver.save()

        return user
Ejemplo n.º 2
0
def _pages_from_json(request, offering, data):
    with django.db.transaction.atomic():
        try:
            data = data.decode('utf-8-sig')
        except UnicodeDecodeError:
            raise ValidationError("Bad UTF-8 data in file.")
            
        try:
            data = json.loads(data)
        except ValueError as e:
            raise ValidationError('JSON decoding error.  Exception was: "' + str(e) + '"')
        
        if not isinstance(data, dict):
            raise ValidationError('Outer JSON data structure must be an object.')
        if 'userid' not in data or 'token' not in data:
            raise ValidationError('Outer JSON data object must contain keys "userid" and "token".')
        if 'pages' not in data:
            raise ValidationError('Outer JSON data object must contain keys "pages".')
        if not isinstance(data['pages'], list):
            raise ValidationError('Value for "pages" must be a list.')
        
        try:
            user = Person.objects.get(userid=data['userid'])
            member = Member.objects.exclude(role='DROP').get(person=user, offering=offering)
        except (Person.DoesNotExist, Member.DoesNotExist):
            raise ValidationError('Person with that userid does not exist.')
        
        if 'pages-token' not in user.config or user.config['pages-token'] != data['token']:
            e = ValidationError('Could not validate authentication token.')
            e.status = 403
            raise e
        
        # if we get this far, the user is authenticated and we can start processing the pages...
        
        for i, pdata in enumerate(data['pages']):
            if not isinstance(pdata, dict):
                raise ValidationError('Page #%i entry structure must be an object.' % (i))
            if 'label' not in pdata:
                raise ValidationError('Page #%i entry does not have a "label".' % (i))
            
            # handle changes to the Page object
            pages = Page.objects.filter(offering=offering, label=pdata['label'])
            if pages:
                page = pages[0]
                old_ver = page.current_version()
            else:
                page = Page(offering=offering, label=pdata['label'])
                old_ver = None

            # check write permissions
            
            # mock the request object enough to satisfy _check_allowed()
            class FakeRequest(object):
                is_authenticated = True
            fake_request = FakeRequest()
            fake_request.user = FakeRequest()
            fake_request.user.username = user.userid

            if old_ver:
                m = _check_allowed(fake_request, offering, page.can_write, page.editdate())
            else:
                m = _check_allowed(fake_request, offering, offering.page_creators())
            if not m:
                raise ValidationError('You can\'t edit page #%i.' % (i))
            
            # handle Page attributes
            if 'can_read' in pdata:
                if type(pdata['can_read']) != str or pdata['can_read'] not in ACL_DESC:
                    raise ValidationError('Page #%i "can_read" value must be one of %s.'
                                          % (i, ','.join(list(ACL_DESC.keys()))))
                
                page.can_read = pdata['can_read']

            if 'can_write' in pdata:
                if type(pdata['can_write']) != str or pdata['can_write'] not in WRITE_ACL_DESC:
                    raise ValidationError('Page #%i "can_write" value must be one of %s.'
                                          % (i, ','.join(list(WRITE_ACL_DESC.keys()))))
                if m.role == 'STUD':
                    raise ValidationError('Page #%i: students can\'t change can_write value.' % (i))
                page.can_write = pdata['can_write']
            
            if 'new_label' in pdata:
                if type(pdata['new_label']) != str:
                    raise ValidationError('Page #%i "new_label" value must be a string.' % (i))
                if m.role == 'STUD':
                    raise ValidationError('Page #%i: students can\'t change label value.' % (i))
                if Page.objects.filter(offering=offering, label=pdata['new_label']):
                    raise ValidationError('Page #%i: there is already a page with that "new_label".' % (i))

                page.label = pdata['new_label']

            page.save()

            # handle PageVersion changes
            ver = PageVersion(page=page, editor=member)
            
            if 'title' in pdata:
                if type(pdata['title']) != str:
                    raise ValidationError('Page #%i "title" value must be a string.' % (i))
                
                ver.title = pdata['title']
            elif old_ver:
                ver.title = old_ver.title
            else:
                raise ValidationError('Page #%i has no "title" for new page.' % (i))

            if 'comment' in pdata:
                if type(pdata['comment']) != str:
                    raise ValidationError('Page #%i "comment" value must be a string.' % (i))
                
                ver.comment = pdata['comment']

            if 'use_math' in pdata:
                if type(pdata['use_math']) != bool:
                    raise ValidationError('Page #%i "comment" value must be a boolean.' % (i))

                ver.set_math(pdata['use_math'])

            if 'markup' in pdata:
                if isinstance(pdata['markup'], str):
                    raise ValidationError('Page #%i "markup" value must be a string.' % (i))

                ver.set_markup(pdata['markup'])

            if 'wikitext-base64' in pdata:
                if type(pdata['wikitext-base64']) != str:
                    raise ValidationError('Page #%i "wikitext-base64" value must be a string.' % (i))
                try:
                    wikitext = base64.b64decode(pdata['wikitext-base64']).decode('utf8')
                except TypeError:
                    raise ValidationError('Page #%i "wikitext-base64" contains bad base BASE64 data.' % (i))
                
                ver.wikitext = wikitext
            elif 'wikitext' in pdata:
                if type(pdata['wikitext']) != str:
                    raise ValidationError('Page #%i "wikitext" value must be a string.' % (i))
                
                ver.wikitext = pdata['wikitext']
            elif old_ver:
                ver.wikitext = old_ver.wikitext
            else:
                raise ValidationError('Page #%i has no wikitext for new page.' % (i))

            ver.save()
        
        return user