/**
* PODD is an OWL ontology database used for scientific project management
*
* Copyright (C) 2009-2013 The University Of Queensland
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
package com.github.podd.resources;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import org.openrdf.OpenRDFException;
import org.openrdf.model.Model;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.impl.LinkedHashModel;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.Rio;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.ByteArrayRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.Variant;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.resource.ResourceException;
import org.restlet.security.User;
import com.github.ansell.restletutils.RestletUtilRole;
import com.github.ansell.restletutils.SesameRealmConstants;
import com.github.podd.restlet.PoddAction;
import com.github.podd.restlet.PoddSesameRealm;
import com.github.podd.restlet.PoddWebServiceApplication;
import com.github.podd.restlet.RestletUtils;
import com.github.podd.utils.PODD;
import com.github.podd.utils.PoddRoles;
import com.github.podd.utils.PoddUser;
import com.github.podd.utils.PoddUserStatus;
import com.github.podd.utils.PoddWebConstants;
/**
*
* User Add resource
*
* @author kutila
*
*/
public class UserAddResourceImpl extends AbstractUserResourceImpl
{
/**
* Handle an HTTP POST request submitting RDF data to create a new PoddUser. This method can
* only add one user per request. On successful addition of a user, the new user's unique URI is
* returned encapsulated in RDF.
*/
@Post("rdf|rj|json|ttl")
public Representation addUserRdf(final Representation entity, final Variant variant) throws ResourceException
{
// check authentication first
this.checkAuthentication(PoddAction.USER_CREATE);
this.log.info("In addUserRdf");
final PoddSesameRealm nextRealm = ((PoddWebServiceApplication)this.getApplication()).getRealm();
URI newUserUri = null;
PoddUser newUser = null;
try
{
// - get input stream with RDF content
final InputStream inputStream = entity.getStream();
final RDFFormat inputFormat =
Rio.getParserFormatForMIMEType(entity.getMediaType().getName(), RDFFormat.RDFXML);
final Model newUserModel = Rio.parse(inputStream, "", inputFormat);
this.log.info("About to create user from model");
// - create new PoddUser and add to Realm
newUser = PoddUser.fromModel(newUserModel, true, false, false);
// If we didn't get a secret, then do not activate their login at
// this stage
if(newUser.getSecret() == null)
{
newUser.setUserStatus(PoddUserStatus.INACTIVE);
}
this.log.info("About to check if user already exists");
if(nextRealm.findUser(newUser.getIdentifier()) != null)
{
throw new ResourceException(Status.CLIENT_ERROR_CONFLICT, "User already exists");
}
newUserUri = nextRealm.addUser(newUser);
this.log.info("Added new User <{}> <{}>", newUser.getIdentifier(), newUserUri);
// - map Roles for the new User
// - add Project Creator Role if nothing else has been specified
if(!newUserModel.contains(null, RDF.TYPE, SesameRealmConstants.OAS_ROLEMAPPING))
{
nextRealm.map(newUser, PoddRoles.PROJECT_CREATOR.getRole());
}
for(final Resource mappingUri : newUserModel.filter(null, RDF.TYPE, SesameRealmConstants.OAS_ROLEMAPPING)
.subjects())
{
final URI roleUri =
newUserModel.filter(mappingUri, SesameRealmConstants.OAS_ROLEMAPPEDROLE, null).objectURI();
final RestletUtilRole role = PoddRoles.getRoleByUri(roleUri);
final URI mappedObject = newUserModel.filter(mappingUri, PODD.PODD_ROLEMAPPEDOBJECT, null).objectURI();
this.log.debug("Mapping <{}> to Role <{}> with Optional Object <{}>", newUser.getIdentifier(),
role.getName(), mappedObject);
if(mappedObject != null)
{
nextRealm.map(newUser, role.getRole(), mappedObject);
}
else
{
nextRealm.map(newUser, role.getRole());
}
}
// - check the User was successfully added to the Realm
final PoddUser findUser = nextRealm.findUser(newUser.getIdentifier());
if(findUser == null)
{
throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Failed to add user");
}
}
catch(final IOException | OpenRDFException e)
{
this.log.error("Error creating user", e);
throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "There was a problem with the input", e);
}
// - prepare response
final ByteArrayOutputStream output = new ByteArrayOutputStream(8096);
final RDFFormat outputFormat =
Rio.getWriterFormatForMIMEType(variant.getMediaType().getName(), RDFFormat.RDFXML);
try
{
final Model model = new LinkedHashModel();
model.add(newUserUri, SesameRealmConstants.OAS_USERIDENTIFIER,
PODD.VF.createLiteral(newUser.getIdentifier()));
Rio.write(model, output, outputFormat);
}
catch(final OpenRDFException e)
{
this.log.error("Error generating response entity", e);
throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Could not create response");
}
return new ByteArrayRepresentation(output.toByteArray(), MediaType.valueOf(outputFormat.getDefaultMIMEType()));
}
@Get
public Representation getUserAddPageHtml(final Representation entity) throws ResourceException
{
this.log.info("addUserHtml");
final User user = this.getRequest().getClientInfo().getUser();
this.log.info("authenticated user: {}", user);
// identify needed Action
this.checkAuthentication(PoddAction.USER_CREATE);
// completed checking authorization
final Map<String, Object> dataModel = RestletUtils.getBaseDataModel(this.getRequest());
dataModel.put("contentTemplate", "admin_createUser.html.ftl");
dataModel.put("pageTitle", "Add PODD User Page");
dataModel.put("title", "Create User");
dataModel.put("authenticatedUsername", user.getIdentifier());
final PoddUserStatus[] statuses = PoddUserStatus.values();
dataModel.put("statusList", statuses);
// Output the base template, with contentTemplate from the dataModel
// defining the
// template to use for the content in the body of the page
return RestletUtils.getHtmlRepresentation(
this.getPoddApplication().getPropertyUtil()
.get(PoddWebConstants.PROPERTY_TEMPLATE_BASE, PoddWebConstants.DEFAULT_TEMPLATE_BASE),
dataModel, MediaType.TEXT_HTML, this.getPoddApplication().getTemplateConfiguration());
}
}