def live_html(request, address): ''' Get the HTML of a live copy of a document This should be generalised and/or merge wiith the `content` view (which also gets (and sets) HTML). ''' api = API(request) if api.get: # First, check access rights component = Component.get( id=None, address=address, user=request.user, action=READ ) # Get HTML from broker response = requests.get('http://10.0.1.75:7315/' + address + '@live?format=html') if response.status_code != 200: raise Exception(response.text) else: if api.browser: response = HttpResponse(response.json()['data'], content_type='text/html') response['Content-Disposition'] = 'attachment; filename="document.html"' return response else: return api.respond(data=response.json()) return api.respond_bad()
def collaborate(request, address): ''' Connect to a live collaboration clone via a Websocket connection ''' api = API(request) if api.get: if not request.user.is_authenticated(): return api.respond_signin() else: # Check that the permit is correct for this address and user # TODO add a salt if compare_digest( str(request.GET.get('permit', '')), hmac.new(settings.SECRET_KEY, address + ':' + request.user.username).hexdigest() ): url = '/internal-collaboration-websocket/%s:%s' % ( # TODO when we have multiple collaboration servers, find the IP one for the one hostong # this address '10.0.1.75', 7315 ) response = HttpResponse('X-Accel-Redirect : %s' % url) response['X-Accel-Redirect'] = url return response else: raise Http404() return api.respond_bad()
def ping(request, address): ''' Ping the component's session. Returns the session id since that could change ''' api = API(request) if api.put: if not request.user.is_authenticated(): return api.respond_signin() else: component = Component.get( id=None, user=request.user, action=READ, address=address ) session = component.activate( user=request.user ) session.ping() return api.respond({ 'session': session.id }) return api.respond_bad()
def boot(request, address): ''' Boot up a component ''' api = API(request) if api.put: component = Component.get( id=None, user=request.user, action=READ, address=address ) action, grantor = component.rights(request.user) if action >= EXECUTE: api.user_ensure() session = component.activate( user=request.user ) else: session = None return api.respond({ 'rights': { 'action': action_string(action), 'grantor': grantor.serialize(user=request.user) if grantor else None }, 'session': session.serialize(user=request.user) if session else None }) return api.respond_bad()
def method(request, address, method): ''' A general view for calling methods on components that are hosted in a session. Will launch a new session for a component if necessary. Not all component methods need an active session so views should be explicitly provided for those below. ''' api = API(request) if api.put: if not request.user.is_authenticated(): return api.respond_signin() else: component = Component.get( id=None, user=request.user, action=READ, # TODO : allow for alternative rights address=address ) session = component.activate( user=request.user ) status, body = session.request( resource=address, verb=request.method, method=method, data=request.body ) return api.respond( data=body, raw=True, status=status ) return api.respond_bad()
def live(request, address): ''' Open the live collaboration clone for the component. ''' api = API(request) if api.get: # First, check access rights component = Component.get( id=None, address=address, user=request.user, action=ANNOTATE ) payload = {} # Then, see if a live collaboration clone already exists # Get the snapshot data # TODO: In the future there may be several collaboration servers response = requests.get('http://10.0.1.75:7315/' + address + '@live') if response.status_code == 404: response = requests.post('http://10.0.1.75:7315/', json = { 'schemaName': 'stencila-document', 'documentId': address + '@live', 'format': 'html', 'content': component.content_get('html')['content'] }) if response.status_code != 200: raise Exception(response.text) payload['snapshot'] = response.json() # Insert the collaboration websocket URL if settings.MODE == 'local': # It's not possible to do a Websocket redirect (without Nginx's 'X-Accel-Redirect') so # in development just give direct WS URL of collaboration server ws = 'ws://10.0.1.75:7315' else: ws = 'wss://stenci.la' ws += '/%s@collaborate?permit=%s' % ( address, hmac.new(settings.SECRET_KEY, address + ':' + request.user.username).hexdigest() ) payload['collabUrl'] = ws # Insert the user and access rights action, grantor = component.rights(request.user) payload['user'] = request.user.username payload['rights'] = action_string(action) # Render template with snapshot data embedded in it return api.respond( template = 'components/live.html', context = { 'type': 'document', 'payload': json.dumps(payload) } ) return api.respond_bad()
def deactivate(request, address): ''' Dectivate a component by stopping the currently active session for it ''' api = API(request) if api.put: if not request.user.is_authenticated(): return api.respond_signin() else: component = Component.get( id=None, user=request.user, action=READ, address=address ) session = component.deactivate( user=request.user ) return api.respond(session) return api.respond_bad()
def new(request): """ List session types, create a new session, launch it and redirect the user to it's page """ api = API(request) if api.get: return api.respond( template="sessions/new.html", context={ "sessions": Session.list(user=request.user, filter={"active": True}).count(), "types": SessionType.objects.order_by("rank").all(), "images": SessionImage.objects.all(), }, ) elif api.post: session = Session.launch(user=request.user, type_id=api.required("type"), image_name=api.required("image")) return api.respond_created(url=session.url()) return api.respond_bad()
def session(request, address): ''' Get the session, if any, for a component ''' api = API(request) if api.put: if not request.user.is_authenticated(): return api.respond_signin() else: component = Component.get( id=None, user=request.user, action=READ, address=address ) session = component.session( user=request.user, required=False ) if session and session.active: session.update() return api.respond(session) return api.respond_bad()
def accept(request, string): """ @brief View for accepting an invitation @param request The request @param string The string """ api = API(request) # Get the invitation try: invitation = Invitation.objects.get(string=string) except Invitation.DoesNotExist: return api.raise_not_found() # If the invitatation has already expired, let the user know if invitation.sent + datetime.timedelta(days=invitation.expiry) < timezone.now(): return render(request, 'invitations/expired.html', dict( invitation=invitation )) # Check whether the user need to be authenticated first if not request.user.is_authenticated(): authed = False elif request.user.details.guest: # Logout the guest # TODO it would be better to "join up" the guest authed = False else: authed = True if authed: # Add the user to the key and redirect them to the path invitation.key.users.add(request.user) invitation.accepted = timezone.now() invitation.accepter = request.user invitation.save() return redirect(invitation.path) else: # Authenticate the user... if invitation.accepted: # Don't Offer the "express" login where we create # a new user if this invitation has already been accepted express_username = None else: # Create a username for "express" signin base = invitation.invitee.split('@')[0] express_username = base trials = 0 while True: if User.objects.filter(username=express_username).count() == 0: break trials += 1 if trials > 1000000: raise Exception("Maximum number of ") express_username = '******' %(base, trials) # URL for redirect when using third party account # to login (come back to this view and get redirected) next = '/invitations/%s/accept' % string if api.get: # Render athentication forms return render(request, 'invitations/accept.html', dict( invitation=invitation, next=next, userpass_form=AuthenticationForm(), express_username=express_username )) elif api.post: if request.POST.get('userpass_signin'): # Attempt to signin with username/password form = AuthenticationForm(data=request.POST) if not form.is_valid(): # Display errors return render(request, 'invitations/accept.html', dict( invitation=invitation, next=next, userpass_form=form, express_username=express_username )) else: # Login the user and then proceed with accept view login(request, form.get_user()) # Continue recursively return accept(request, string) elif express_username and request.POST.get('express_signin'): # Create a new user and log them in user = User.objects.create_user( username=express_username, email=invitation.invitee ) user.backend = 'django.contrib.auth.backends.ModelBackend' login(request, user) # Continue recursively return accept(request, string) else: # Some thing else, just go back the page return redirect(next) else: return api.respond_bad()