package com.pugh.sockso.web.action; import com.pugh.sockso.Constants; import com.pugh.sockso.Utils; import com.pugh.sockso.Validater; import com.pugh.sockso.db.Database; import com.pugh.sockso.music.CollectionManager; import com.pugh.sockso.music.CollectionManagerListener; import com.pugh.sockso.music.Files; import com.pugh.sockso.web.Request; import com.pugh.sockso.web.User; import com.pugh.sockso.web.UploadFile; import com.pugh.sockso.web.BadRequestException; import com.pugh.sockso.templates.web.TUpload; import com.pugh.sockso.templates.web.TUploadComplete; import com.pugh.sockso.resources.Locale; import com.pugh.sockso.Properties; import java.io.File; import java.io.IOException; import java.sql.SQLException; import org.apache.log4j.Logger; import com.google.inject.Inject; public class Uploader extends BaseAction { private static final Logger log = Logger.getLogger( Uploader.class ); private final CollectionManager cm; @Inject public Uploader( final CollectionManager cm ) { this.cm = cm; } /** * handles requests for this controller * */ public void handleRequest() throws IOException, BadRequestException, SQLException { final Request req = getRequest(); final String type = req.getUrlParam( 1 ); checkPermissions(); if ( type.equals("do") ) uploadFile(); else showUploadForm(); } /** * handles uploading and storing of a file from the user, then shows * them a confirmation page when it's done * * @param req request object * @param res response object * @param user current user * @param locale the selected locale * */ private void uploadFile() throws BadRequestException { checkUploadLooksOk(); final Properties p = getProperties(); final Request req = getRequest(); final Locale locale = getLocale(); final UploadFile file = req.getFile( "musicFile" ); final String artist = req.getArgument( "artist" ); final String album = req.getArgument( "album" ); final String track = req.getArgument( "title" ); // if we get here everything looks good, so lets try and save the file try { // make sure we've a directory to put the track in final Database db = getDatabase(); final File dir = new File( Utils.getUploadsPath(db,p) + "/"+artist+" - "+album ); if ( !dir.exists() ) if ( !dir.mkdir() ) throw new BadRequestException( locale.getString("www.error.cantCreateTrackFolder"), 500 ); // write the track to disk final File tempFile = file.getTemporaryFile(); final File newFile = new File( getNewUploadFilename(dir,track,Utils.getExt(file.getFilename())) ); tempFile.renameTo( newFile ); // rescan the folder to add new track to collection final int collectionId = Integer.parseInt( p.get(Constants.WWW_UPLOADS_COLLECTION_ID) ); cm.scanDirectory( collectionId, dir ); cm.fireCollectionManagerEvent( CollectionManagerListener.UPDATE_COMPLETE, "Collection Updated!" ); // show user confirmation final TUploadComplete tpl = new TUploadComplete(); tpl.setProperties( p ); tpl.setUser( getUser() ); tpl.setLocale( getLocale() ); getResponse().showHtml( tpl.makeRenderer() ); } catch ( IOException e ) { log.debug( e ); } } /** * does some error checking to see if the upload looks ok, checks required * arguments, etc... if something is missing then throws an exception * * @throws com.pugh.sockso.web.BadRequestException * */ private void checkUploadLooksOk() throws BadRequestException { final Request req = getRequest(); final Locale locale = getLocale(); final UploadFile file = req.getFile( "musicFile" ); if ( file == null ) throw new BadRequestException( locale.getString("www.error.noFileUploaded") ); // check mime type to see if it looks ok final String contentType = file.getContentType(); log.debug( "File content type: " + contentType ); if ( !Files.isValidMimeType(contentType) ) throw new BadRequestException( locale.getString("www.error.unsupportedAudioFormat") ); // check required fields final Database db = getDatabase(); final Validater v = new Validater( db ); final String artist = req.getArgument( "artist" ); final String album = req.getArgument( "album" ); final String track = req.getArgument( "title" ); if ( !v.checkRequiredFields( new String[] { artist, album, track }) ) throw new BadRequestException( locale.getString("www.error.missingField") ); } /** * this method tries to get an unused filename on disk that we can use * to write the uploaded file to. it tries appending 1,2,3, etc... onto * the track name. it'll try a maximum of 100 times then give up * * @param dir the directory for the file * @param track the track title of the file * @param ext the file's extension * * @return absolute path if we can get one, exception otherwise * * @throws com.pugh.sockso.web.BadRequestException * */ private String getNewUploadFilename( final File dir, final String track, final String ext ) throws BadRequestException { final Locale locale = getLocale(); int i = -1; // only try 100 times to avoid infinite loop, is 100 enough? probably. while ( i++ < 100 ) { final File file = new File( dir.getAbsolutePath() + "/" + track + (i==0?"":i) + "." + ext ); if ( !file.exists() ) return file.getAbsolutePath(); } throw new BadRequestException( locale.getString("www.error.couldNotCreateUniqueFilename"), 500 ); } /** * checks that everything is ok for doing uploads, ie. they're enabled, the * user is logged in if required, etc... * * @throws BadRequestException * */ private void checkPermissions() throws BadRequestException { final User user = getUser(); final Locale locale = getLocale(); final Properties p = getProperties(); // check uploads are enabled Utils.checkFeatureEnabled( p, "uploads.enabled" ); // if the user isn't logged in then make sure that anonymous // uploads have been enabled if ( user == null ) if ( !p.get(Constants.WWW_UPLOADS_ALLOW_ANONYMOUS).equals(Properties.YES) ) throw new BadRequestException( locale.getString("www.error.noAnonymousUploads"), 403 ); // check there is a valid collection set for uploads final Database db = getDatabase(); final String uploadsPath = Utils.getUploadsPath( db, p ); if ( uploadsPath.equals("") ) throw new BadRequestException( locale.getString("www.error.noUploadsDirectory"), 500 ); final File uploadsDir = new File( uploadsPath ); if ( !uploadsDir.canWrite() ) throw new BadRequestException( locale.getString("www.error.uploadsDirNotWritable"), 500 ); } /** * shows the form where users can upload music * */ protected void showUploadForm() throws IOException, BadRequestException, SQLException { final TUpload tpl = new TUpload(); getResponse().showHtml( tpl ); } }