diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/ScriptRepository.h b/Code/Mantid/Framework/API/inc/MantidAPI/ScriptRepository.h index 847b2cd83a2b57d3a99b4ea747ef4660d84479c7..968898b08ab952677379491ebb3bba34b5a7dd4f 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/ScriptRepository.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/ScriptRepository.h @@ -471,10 +471,7 @@ They will work as was expected for folders @ref folders-sec. it it necessary that it identifies who was responsible for changing the file. - @param description is an optional argument, because, as - explained at @ref script-description-sec it may be already inside the - file. But, if the description is given, it will be inserted to the local - file (if it is a script) or to the README file inside the folder. + @param email An string that identifies the email of the author. @exception ScriptRepoException may be triggered for an attempt to publish an @@ -486,7 +483,7 @@ They will work as was expected for folders @ref folders-sec. */ virtual void upload(const std::string & file_path, const std::string & comment, const std::string & author, - const std::string & description = std::string()) = 0; + const std::string & email) = 0; /** Define the file patterns that will not be listed in listFiles. This is important to force the ScriptRepository to not list hidden files, diff --git a/Code/Mantid/Framework/Kernel/CMakeLists.txt b/Code/Mantid/Framework/Kernel/CMakeLists.txt index 96d3beb6fe4c7b778ca3466009d408e7d721d9e1..b766f298a4782b8885ca566591d05c1cd194c27e 100644 --- a/Code/Mantid/Framework/Kernel/CMakeLists.txt +++ b/Code/Mantid/Framework/Kernel/CMakeLists.txt @@ -383,6 +383,7 @@ set ( PYTHONALG_DIRS "${MANTID_ROOT}/Framework/PythonAPI/PythonAlgorithms;${MANT set ( PYTHONPLUGIN_DIRS "${MANTID_ROOT}/Framework/PythonAPI/PythonAlgorithms;${MANTID_ROOT}/Framework/PythonInterface/plugins" ) set ( DATADIRS ${MANTID_ROOT}/../../Test/AutoTestData;${MANTID_ROOT}/instrument ) set ( COLORMAPS_FOLDER ${MANTID_ROOT}/Installers/colormaps/ ) +SET ( MANTIDPUBLISHER "http://upload.mantidproject.org/scriptrepository/payload/publish_debug" ) # Construct script paths. set ( MANTID_SCRIPTS ${MANTID_ROOT}/scripts ) @@ -456,6 +457,7 @@ set ( PLUGINS ${MANTID_ROOT}/plugins ) set ( PYTHONALG_DIRS ${PLUGINS}/PythonAlgs ) # deprecated set ( PYTHONPLUGIN_DIRS ${PLUGINS}/python ) set ( DATADIRS "" ) +SET ( MANTIDPUBLISHER "http://upload.mantidproject.org/scriptrepository/payload/publish" ) # Construct script paths by replacing the old MANTID_ROOT with the new one. # Unfortunately string (REGEX REPLACE ... )removes the semi-colons so we have to do this in a loop. diff --git a/Code/Mantid/Framework/Properties/Mantid.properties.template b/Code/Mantid/Framework/Properties/Mantid.properties.template index d1ca889279bc97c0a9601c956168a442fde2bbc7..a629dd29127e5bafcb85de1d5ff48f673d3820d2 100644 --- a/Code/Mantid/Framework/Properties/Mantid.properties.template +++ b/Code/Mantid/Framework/Properties/Mantid.properties.template @@ -200,8 +200,8 @@ algorithms.categories.hidden=Workflow\\Inelastic\\UsesPropertyManager;Workflow\\ # ScriptRepository Properties: -# Url for the WebServer that support the upload of the files that the users want to share (not in usage) -UploaderWebServer = +# Url for the WebServer that support the upload of the files that the users want to share +UploaderWebServer = @MANTIDPUBLISHER@ # Local system path for the script repository. ScriptLocalRepository = # Url for the remote script repository. diff --git a/Code/Mantid/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h b/Code/Mantid/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h index c0f5d8e4fff9cff5026fc3809f4d8a8d8b5e43df..f20983fcd9f4b46b86543ffadcab1c52414758be 100644 --- a/Code/Mantid/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h +++ b/Code/Mantid/Framework/ScriptRepository/inc/MantidScriptRepository/ScriptRepositoryImpl.h @@ -99,7 +99,7 @@ namespace API{ void upload(const std::string & file_path, const std::string & comment, const std::string & author, - const std::string & description = std::string()); + const std::string & email); /* Return true if there is a local repository installed*/ bool isValid(void); @@ -135,6 +135,8 @@ namespace API{ std::string local_repository; /// URL for the remote repository, usually: std::string remote_url; + /// URL for the upload + std::string remote_upload; private: diff --git a/Code/Mantid/Framework/ScriptRepository/src/ScriptRepositoryImpl.cpp b/Code/Mantid/Framework/ScriptRepository/src/ScriptRepositoryImpl.cpp index e2ab75cf20c32108d0500f48c12809018cfb4e44..79290bda08d5aec3e3c55071ed81233d783ec70b 100644 --- a/Code/Mantid/Framework/ScriptRepository/src/ScriptRepositoryImpl.cpp +++ b/Code/Mantid/Framework/ScriptRepository/src/ScriptRepositoryImpl.cpp @@ -18,6 +18,9 @@ using Mantid::Kernel::ConfigServiceImpl; #include <Poco/Exception.h> #include <Poco/Net/HTTPResponse.h> #include <Poco/Net/NetException.h> +#include <Poco/Net/HTMLForm.h> +#include "Poco/Net/FilePartSource.h" + // Visual Studion compains with the inclusion of Poco/FileStream // disabling this warning. @@ -51,10 +54,6 @@ namespace Mantid namespace API { - static void notImplemented(){ - throw ScriptRepoException("This method is not implemented yet"); - }; - static ScriptRepoException pocoException(const std::string & info, Poco::Exception & ex){ std::stringstream ss; @@ -110,10 +109,11 @@ namespace API { // get the local path and the remote path std::string loc, rem; + ConfigServiceImpl & config = ConfigService::Instance(); + remote_upload = config.getString("UploaderWebServer"); if (local_rep.empty() || remote.empty()){ - ConfigServiceImpl & config = ConfigService::Instance(); loc = config.getString("ScriptLocalRepository"); - rem = config.getString("ScriptRepository"); + rem = config.getString("ScriptRepository"); }else{ local_repository = local_rep; remote_url = remote; @@ -440,7 +440,7 @@ namespace API st |= LOC; // the file is remote_changed if the date of the pub_date file is // diferent from the local downloaded pubdate. - if (entry.pub_date != entry.downloaded_pubdate) + if (entry.pub_date > entry.downloaded_pubdate) st |= REMO; @@ -691,20 +691,131 @@ namespace API } /** - @todo Describe - + * Uploads one file to the ScriptRepository web server, pushing, indirectly, to the + * git repository. It will send in a POST method, the file and the following fields: + * - author : Will identify the author of the change + * - email: Will identify the email of the author + * - comment: Description of the nature of the file or of the update + * + * It will them upload to the URL pointed to UploaderWebServer. It will them receive a json file + * with some usefull information about the success or failure of the attempt to upload. + * In failure, it will be converted to an appropriated ScriptRepoException. */ void ScriptRepositoryImpl::upload(const std::string & file_path, const std::string & comment, const std::string & author, - const std::string & description) + const std::string & email) { - UNUSED_ARG(file_path); - UNUSED_ARG(comment); - UNUSED_ARG(author); - UNUSED_ARG(description); - notImplemented(); + using namespace Poco::Net; + try{ + g_log.notice() << "ScriptRepository uploading " << file_path << " ..." << std::endl; + Poco::URI uri(remote_upload); + std::string path(uri.getPathAndQuery()); + HTTPClientSession session(uri.getHost(), uri.getPort()); + HTTPRequest req(HTTPRequest::HTTP_POST, path, + HTTPMessage::HTTP_1_0); + HTMLForm form(HTMLForm::ENCODING_MULTIPART); + + // add the fields author, email and comment + form.add("author",author); + form.add("mail", email); + form.add("comment",comment); + + // deal with the folder + std::string relative_path = convertPath(file_path); + std::string absolute_path = local_repository + relative_path; + std::string folder = "./"; + size_t pos = relative_path.rfind('/'); + if (pos != std::string::npos) + folder += std::string(relative_path.begin(), relative_path.begin() + pos); + if (folder[folder.size()-1] != '/') + folder += "/"; + g_log.information() << "Uploading to folder: " << folder << std::endl; + form.add("path",folder); + + // inserting the file + FilePartSource * m_file = new FilePartSource(absolute_path); + form.addPart("file",m_file); + form.prepareSubmit(req); + + // get the size of everything + std::stringstream sst; + form.write(sst); + // move back to the begining of the file + m_file->stream().clear(); + m_file->stream().seekg(0,std::ios::beg); + // set the size + req.setContentLength((int)sst.str().size()); + + std::ostream& ostr = session.sendRequest(req); + // send the request. + ostr << sst.str(); + + HTTPResponse response; + std::istream & rs = session.receiveResponse(response); + + g_log.information() << "ScriptRepository upload status: " + << response.getStatus() << " " << response.getReason() << std::endl; + std::stringstream answer; + { // remove the status message from the end of the reply, in order not to get exception from the read_json parser + std::stringstream server_reply; + std::string server_reply_str; + Poco::StreamCopier::copyStream(rs, server_reply); + server_reply_str= server_reply.str(); + size_t pos = server_reply_str.rfind("}"); + if (pos != std::string::npos) + answer << std::string(server_reply_str.begin() , server_reply_str.begin() + pos + 1); + else + answer << server_reply_str; + } + g_log.debug() << "Form Output: " << answer.str() << std::endl; + + std::string info; + std::string detail; + std::string published_date; + + ptree pt; + try{ + read_json(answer, pt); + info = pt.get<std::string>("message",""); + detail = pt.get<std::string>("detail",""); + published_date = pt.get<std::string>("pub_date",""); + std::string cmd = pt.get<std::string>("shell",""); + if (!cmd.empty()) + detail.append("\nFrom Command: ").append(cmd); + + }catch (boost::property_tree::json_parser_error & ex){ + throw ScriptRepoException("Bad answer from the Server", + ex.what()); + } + + if (info == "success"){ + g_log.notice() << "ScriptRepository:" << file_path << " uploaded!"<< std::endl; + + // update the file + RepositoryEntry & entry = repo.at(file_path); + { + Poco::File local(absolute_path); + entry.downloaded_date = DateAndTime(Poco::DateTimeFormatter::format(local.getLastModified(), + timeformat)); + // update the pub_date and downloaded_pubdate with the pub_date given by the upload. + // this ensures that the status will be correctly defined. + if (!published_date.empty()) + entry.pub_date = DateAndTime(published_date); + entry.downloaded_pubdate = entry.pub_date; + entry.status = BOTH_UNCHANGED; + } + g_log.information() << "ScriptRepository update local json " << std::endl; + updateLocalJson(file_path, entry); ///FIXME: performance! + + + }else + throw ScriptRepoException(info, detail); + + }catch(Poco::Exception & ex){ + throw ScriptRepoException(ex.displayText(), ex.className()); + } } /** The ScriptRepositoryImpl is set to be valid when the local repository path @@ -853,6 +964,7 @@ namespace API //Configure Poco HTTP Client Session try{ Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort()); + session.setTimeout(Poco::Timespan(2,0));// 2 secconds Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, path, Poco::Net::HTTPMessage::HTTP_1_1); Poco::Net::HTTPResponse response; @@ -1054,8 +1166,12 @@ namespace API // array.push_back(std::make_pair("auto_update",entry.auto_update))); local_json.push_back( std::pair<std::string, boost::property_tree::basic_ptree<std::string,std::string> >(path,array) ); }else{ - local_json.put(std::string(path).append(".downloaded_pubdate"), - entry.downloaded_pubdate.toFormattedString()); + local_json.put( + boost::property_tree::ptree::path_type( std::string(path).append("!downloaded_pubdate"), '!'), + entry.downloaded_pubdate.toFormattedString().c_str()); + local_json.put( + boost::property_tree::ptree::path_type( std::string(path).append("!downloaded_date"), '!'), + entry.downloaded_date.toFormattedString().c_str()); } //g_log.debug() << "Update LOCAL JSON FILE" << std::endl; #if defined(_WIN32) || defined(_WIN64) diff --git a/Code/Mantid/MantidQt/API/src/RepoModel.cpp b/Code/Mantid/MantidQt/API/src/RepoModel.cpp index 4dea511302d80ac9386f4ff54ff92977b834a297..6b74640d5765f2df871de78842744f3be92812d9 100644 --- a/Code/Mantid/MantidQt/API/src/RepoModel.cpp +++ b/Code/Mantid/MantidQt/API/src/RepoModel.cpp @@ -315,6 +315,13 @@ bool RepoModel::setData(const QModelIndex & index, const QVariant & value, } }else if (action == "Upload"){ QWidget * father = qobject_cast<QWidget*>(QObject::parent()); + if (repo_ptr->fileInfo(path).directory){ + QMessageBox::information(father, + "Not Supported", + "The current version does not support uploading recursively. Please, upload one-by-one"); + return false; + }; + UploadForm * form = new UploadForm(QString::fromStdString(path), father); QSettings settings; settings.beginGroup("Mantid/ScriptRepository");