diff --git a/.github/workflows/docker-CI.yml b/.github/workflows/docker-CI.yml index cf97e05..eebbe90 100644 --- a/.github/workflows/docker-CI.yml +++ b/.github/workflows/docker-CI.yml @@ -2,7 +2,7 @@ name: Docker Build and Push on: push: - branches: [ master, develop , unnamed-module-fix ] + branches: [ master, develop ] jobs: test: diff --git a/README.md b/README.md index a169e93..55bbb07 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,14 @@ This service can be used to conduct surveys from LimeSurvey with bots created by Build -------- + Execute the following command on your shell: ```shell -gradle clean build +gradle build ``` +Make sure the ``shs`` database exists. If not, create a new database with the same name Start -------- @@ -22,17 +24,14 @@ bin/start_network.bat ``` Unix/Mac: + ```shell bin/start_network.sh ``` - - - -# Starting a survey bot on slack: +# Starting a survey bot on slack ### Creating a slack app - To create a survey chatbot, first a slack app needs to be created. Creating a classic bot app is possible [here](https://api.slack.com/apps?new_classic_app=1). (Wait for the app creation window to pop up, do not click on the green "Create New App" button). Since the las2peersocial-bot-manager-service uses RTM, a classic app, instead of a new app, is needed. @@ -46,30 +45,27 @@ Since the las2peersocial-bot-manager-service uses RTM, a classic app, instead of - channels:read - chat:write:bot - + - bot - + - users:read.email (users:read included) - incoming-webhook should already be there. If not add under basic information: incoming webhooks: activate incoming webhooks sliding button - Please do not update scopes! - + Now install the app to your wished workspace. After this a token will be generated which is used in the redirect url. 1. Find the bot token: On the left side: OAuth and Permissons, the bot user oauth token (starting with xoxb). - + 2. Activate interactive components (on the left side: Basic Information: Add features and functionality, Interactive Components. After activating this feature, a Request URL is needed.) 3. Configuring the request url: - The ip address and port where slack posts the request (the address from the sbfmanager), slack app token, the bot name from the frontend, the instance name from the frontend and the buttonintent text are needed. - http://ipAddress:port/SBFManager/bots/botName/appRequestURL/instanceName/buttonIntent/token. - + . - - -### Frontend modeling: +### Frontend modeling 1. Create a bot model by following the guide [here](https://github.com/rwth-acis/Social-Bot-Framework). @@ -85,24 +81,24 @@ Now install the app to your wished workspace. After this a token will be generat - The bot actions needs the following action parameters: (all Content Type: String, Static and Parameter Type: body) - * Name: NameOfUser and Content: the username of your "https://limesurvey.tech4comp.dbis.rwth-aachen.de/" account; - * Name: Password and Content: the password of your limesurvey account; - * Name: surveyID and Content: The surveyID of the survey you want to conduct. You can find this by logging into your limesurvey account and then clicking on "List surveys". In the survey list you will see on the very left side the Survey ID. - * Name: buttonIntent and Content: The button intent, which is going to be recognized when participants click on answer buttons - * Name: sbfmUrl and Content: The URL where the social-bot-framework-manager can receive requests - * Name: slackToken and Content: The slack token that has been added to the "Messenger" with type "Slack" as "Authentication Token" - * Name: adminmail and Content: the email of the admin user (Content Type: String and Parameter Type: body) + - Name: NameOfUser and Content: the username of your "https://limesurvey.tech4comp.dbis.rwth-aachen.de/" account; + - Name: Password and Content: the password of your limesurvey account; + - Name: surveyID and Content: The surveyID of the survey you want to conduct. You can find this by logging into your limesurvey account and then clicking on "List surveys". In the survey list you will see on the very left side the Survey ID. + - Name: buttonIntent and Content: The button intent, which is going to be recognized when participants click on answer buttons + - Name: sbfmUrl and Content: The URL where the social-bot-framework-manager can receive requests + - Name: slackToken and Content: The slack token that has been added to the "Messenger" with type "Slack" as "Authentication Token" + - Name: adminmail and Content: the email of the admin user (Content Type: String and Parameter Type: body) 4. It is possible to add routines for sending reminders or sending results to LimeSurvey. - for routine: Action Type: Service, Function Name: reminderRoutine. - + - for LimeSurvey results: Action Type: Service, Function Name:sendResultsToLimesurvey. - for MobSOS surveys results: Action Type: Service, Function Name:sendResultsToMobsosSurveys. - both of them need the action parameters from the main bot actions -### Creating a LimeSurvey Survey: +### Creating a LimeSurvey Survey -enable under Participants settings: "Allow multiple responses or update responses with one token." diff --git a/app/src/main/java/i5/las2peer/services/SurveyHandler/SurveyHandlerService.java b/app/src/main/java/i5/las2peer/services/SurveyHandler/SurveyHandlerService.java index b963e36..0ced658 100644 --- a/app/src/main/java/i5/las2peer/services/SurveyHandler/SurveyHandlerService.java +++ b/app/src/main/java/i5/las2peer/services/SurveyHandler/SurveyHandlerService.java @@ -265,6 +265,115 @@ public Response getTemplate() { return Response.ok().entity(name).build(); } + @POST + @Path("/surveys") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "REPLACE THIS WITH AN APPROPRIATE FUNCTION NAME", notes = "REPLACE THIS WITH YOUR NOTES TO THE FUNCTION") + @ApiResponses(value = { + @ApiResponse(code = HttpURLConnection.HTTP_OK, message = "REPLACE THIS WITH YOUR OK MESSAGE") }) + public Response getSurveys(String input) { + Context.get().monitorEvent(MonitoringEvent.MESSAGE_RECEIVED, input); + + JSONObject response = new JSONObject(); + JSONParser p = new JSONParser(JSONParser.MODE_PERMISSIVE); + + JSONArray completeReturnJSON = new JSONArray(); + + try { + JSONObject bodyInput = (JSONObject) p.parse(input); + System.out.println("received message: " + bodyInput); + + String url = bodyInput.getAsString("url"); + String loginName = bodyInput.getAsString("loginName"); + String loginPassword = bodyInput.getAsString("loginPassword"); + + MiniClient mini = new MiniClient(); + mini.setConnectorEndpoint(url); + HashMap head = new HashMap(); + + ClientResponse miniClientResponse = mini.sendRequest("POST", url, + ("{\"method\": \"get_session_key\", \"params\": [ \"" + loginName + "\", \"" + loginPassword + + "\"], \"id\": 1}"), + MediaType.APPLICATION_JSON, "", head); + if (miniClientResponse.getHttpCode() != 200) { + System.out.println("Error: " + miniClientResponse.getHttpCode()); + return Response.status(miniClientResponse.getHttpCode()).build(); + + } + JSONObject miniresJSON = (JSONObject) p.parse(miniClientResponse.getResponse()); + String sessionKeyString = miniresJSON.getAsString("result"); + + ClientResponse clientResponseQuestionInfo = mini.sendRequest("POST", url, + ("{\"method\": \"list_surveys\", \"params\": [ \"" + sessionKeyString + "\"], \"id\": 1}"), + MediaType.APPLICATION_JSON, "", head); + JSONObject res = (JSONObject) p.parse(clientResponseQuestionInfo.getResponse()); + return Response.ok().entity(res.toJSONString()).build(); + + } catch (Exception e) { + e.printStackTrace(); + } + + response.put("text", completeReturnJSON); + Context.get().monitorEvent(MonitoringEvent.RESPONSE_SENDING.toString()); + return Response.ok().entity(response).build(); + } + + @POST + @Path("/limeSurveyFunction") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "REPLACE THIS WITH AN APPROPRIATE FUNCTION NAME", notes = "REPLACE THIS WITH YOUR NOTES TO THE FUNCTION") + @ApiResponses(value = { + @ApiResponse(code = HttpURLConnection.HTTP_OK, message = "REPLACE THIS WITH YOUR OK MESSAGE") }) + public Response runLimesurveyFunction(String input) { + Context.get().monitorEvent(MonitoringEvent.MESSAGE_RECEIVED, input); + + JSONObject response = new JSONObject(); + JSONParser p = new JSONParser(JSONParser.MODE_PERMISSIVE); + + JSONArray completeReturnJSON = new JSONArray(); + + try { + JSONObject bodyInput = (JSONObject) p.parse(input); + System.out.println("received message: " + bodyInput); + + String url = bodyInput.getAsString("url"); + String loginName = bodyInput.getAsString("loginName"); + String loginPassword = bodyInput.getAsString("loginPassword"); + String command = bodyInput.getAsString("command"); + JSONArray params = (JSONArray) bodyInput.get("params"); + + MiniClient mini = new MiniClient(); + mini.setConnectorEndpoint(url); + HashMap head = new HashMap(); + + ClientResponse miniClientResponse = mini.sendRequest("POST", url, + ("{\"method\": \"get_session_key\", \"params\": [ \"" + loginName + "\", \"" + loginPassword + + "\"], \"id\": 1}"), + MediaType.APPLICATION_JSON, "", head); + JSONObject miniresJSON = (JSONObject) p.parse(miniClientResponse.getResponse()); + String sessionKeyString = miniresJSON.getAsString("result"); + params.add(0, sessionKeyString); // add session key to params + + JSONObject request = new JSONObject(); + request.put("method", command); + request.put("params", params); + request.put("id", 1); + + ClientResponse clientResponseQuestionInfo = mini.sendRequest("POST", url, + (request.toJSONString()), + MediaType.APPLICATION_JSON, "", head); + JSONObject res = (JSONObject) p.parse(clientResponseQuestionInfo.getResponse()); + return Response.ok().entity(res.toJSONString()).build(); + + } catch (Exception e) { + e.printStackTrace(); + } + + response.put("text", completeReturnJSON); + Context.get().monitorEvent(MonitoringEvent.RESPONSE_SENDING.toString()); + return Response.ok().entity(response).build(); + } + @POST @Path("/post/{input}") @Produces(MediaType.TEXT_PLAIN) @@ -282,8 +391,7 @@ public Response postTemplate(@PathParam("input") String myInput) { } @POST - @Path("/getLimeSurveyResponses") - @Consumes(MediaType.TEXT_PLAIN) + @Path("/responses") @Produces(MediaType.APPLICATION_JSON) @ApiOperation( value = "Get results from LimeSurvey.", @@ -314,6 +422,10 @@ public Response limesurveyConnector(String input) { String surveyID = bodyInput.getAsString("surveyID"); String documentType = "json"; + if (surveyID == null) { + return Response.status(HttpURLConnection.HTTP_BAD_REQUEST).entity("surveyID is null").build(); + } + MiniClient mini = new MiniClient(); mini.setConnectorEndpoint(url); HashMap head = new HashMap(); @@ -323,12 +435,25 @@ public Response limesurveyConnector(String input) { String sessionKeyString = miniresJSON.getAsString("result"); // now get question information, to add to response json object - ClientResponse clientResponseQuestionInfo = mini.sendRequest("POST", url, ("{\"method\": \"list_questions\", \"params\": [ \"" + sessionKeyString + "\", \"" + surveyID + "\"], \"id\": 1}"), MediaType.APPLICATION_JSON, "", head); + ClientResponse clientResponseQuestionInfo = mini + .sendRequest( + "POST", url, ("{\"method\": \"list_questions\", \"params\": [ \"" + sessionKeyString + + "\", \"" + surveyID + "\"], \"id\": 1}"), + MediaType.APPLICATION_JSON, "", head); + + if (clientResponseQuestionInfo.getHttpCode() != 200) { + return Response.status(clientResponseQuestionInfo.getHttpCode()) + .entity(clientResponseQuestionInfo.getResponse()).build(); + } + JSONObject questionInfoJSON = (JSONObject) p.parse(clientResponseQuestionInfo.getResponse()); String questionInfo = questionInfoJSON.getAsString("result"); JSONArray questionListJSON = (JSONArray) p.parse(questionInfo); - ClientResponse clientResponse = mini.sendRequest("POST", url, ("{\"method\": \"export_responses\", \"params\": [ \"" + sessionKeyString + "\", \"" + surveyID + "\", \"" + documentType + "\"], \"id\": 1}"), MediaType.APPLICATION_JSON, "", head); + ClientResponse clientResponse = mini.sendRequest( + "POST", url, ("{\"method\": \"export_responses\", \"params\": [ \"" + sessionKeyString + "\", \"" + + surveyID + "\", \"" + documentType + "\"], \"id\": 1}"), + MediaType.APPLICATION_JSON, "", head); JSONObject clientResponseJSON = (JSONObject) p.parse(clientResponse.getResponse()); String encodedFile = clientResponseJSON.getAsString("result"); diff --git a/app/src/test/java/i5/las2peer/services/SurveyHandler/ServiceTest.java b/app/src/test/java/i5/las2peer/services/SurveyHandler/ServiceTest.java index 6df6603..0980583 100644 --- a/app/src/test/java/i5/las2peer/services/SurveyHandler/ServiceTest.java +++ b/app/src/test/java/i5/las2peer/services/SurveyHandler/ServiceTest.java @@ -1,23 +1,10 @@ package i5.las2peer.services.SurveyHandler; -import java.io.*; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; -import java.util.*; - -import i5.las2peer.api.Context; -import i5.las2peer.api.logging.MonitoringEvent; -import i5.las2peer.services.SurveyHandler.database.SurveyHandlerServiceQueries; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.parser.JSONParser; -import org.glassfish.jersey.server.JSONP; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.HashMap; + import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -31,13 +18,9 @@ import i5.las2peer.p2p.LocalNodeManager; import i5.las2peer.security.UserAgentImpl; import i5.las2peer.testing.MockAgentFactory; - -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.parser.JSONParser; /** @@ -554,7 +537,8 @@ public void testLimeSurveyConnector() { client.setConnectorEndpoint(connector.getHttpEndpoint()); client.setLogin(testAgent.getIdentifier(), testPass); - ClientResponse result = client.sendRequest("POST", mainPath + "getLimeSurveyResponses", "{\"loginName\":" + NameOfUser + ",\"url\":" + uri + ",\"surveyID\":" + surveyID + ",\"loginPassword\":" + Password + "}"); + ClientResponse result = client.sendRequest("POST", mainPath + "responses", "{\"loginName\":" + NameOfUser + + ",\"url\":" + uri + ",\"surveyID\":" + surveyID + ",\"loginPassword\":" + Password + "}"); JSONParser p = new JSONParser(); JSONObject resultJSON = (JSONObject) p.parse(result.getResponse()); String resultString = resultJSON.getAsString("text"); diff --git a/etc/initdb.sql b/etc/initdb.sql new file mode 100644 index 0000000..924944f --- /dev/null +++ b/etc/initdb.sql @@ -0,0 +1 @@ +create database shs \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 378f5f3..8f4f188 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ core.version=1.2.2 service.name=i5.las2peer.services.SurveyHandler service.class=SurveyHandlerService -service.version=1.0.1 +service.version=1.1.0 java.version=17 las2peer_user1.name=alice