diff --git a/.eslintrc.js b/.eslintrc.js index 130e66a..6984915 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,6 +30,11 @@ module.exports = { "semi": [ "error", "never" + ], + "key-spacing": [ + "error", { + "beforeColon": false + } ] } } diff --git a/oidc_mock/config/clients.json b/oidc_mock/config/clients.json index cccb0f4..cc7832d 100644 --- a/oidc_mock/config/clients.json +++ b/oidc_mock/config/clients.json @@ -7,7 +7,7 @@ "AllowAccessTokensViaBrowser": true, "RedirectUris": ["http://localhost:8080/logged-in"], "AllowedScopes": ["openid", "profile", "email", "permissions"], - "IdentityTokenLifetime": 3600, + "IdentityTokenLifetime": 36000, "AccessTokenLifetime": 3600, "ClientClaimsPrefix": "" } diff --git a/src/assets/scss/bbmri.scss b/src/assets/scss/bbmri.scss index bcf15a3..b00362d 100644 --- a/src/assets/scss/bbmri.scss +++ b/src/assets/scss/bbmri.scss @@ -15,4 +15,8 @@ $default-text-color: white; .btn-primary { color: white; +} + +.cursor-pointer { + cursor: pointer; } \ No newline at end of file diff --git a/src/components/NegotiationForm.vue b/src/components/NegotiationForm.vue index 8b3f524..49262ec 100644 --- a/src/components/NegotiationForm.vue +++ b/src/components/NegotiationForm.vue @@ -38,7 +38,7 @@ v-for="section in accessCriteria.sections" :key="section.name" :title="section.label" - class="form-step border rounded px-2 py-3 mb-2" + class="form-step border rounded-2 px-2 py-3 mb-2" >
+ - {{ section.label }} + {{ section.label.toUpperCase() }}
- {{ negotiationCriteria[section.name][criteria.name] }} + + {{ negotiationCriteria[section.name][criteria.name].name }} + + + {{ negotiationCriteria[section.name][criteria.name] }} +
@@ -170,7 +183,7 @@ export default { await this.createNegotiation({ data: { requests: [this.requestId], - payload: this.negotiationCriteria + payload: this.negotiationCriteria, } }).then((negotiationId) => { if (negotiationId) { @@ -180,6 +193,12 @@ export default { } }) }, + isAttachment(value) { + return value instanceof File || value instanceof Object + }, + handleFileUpload(event, section, criteria) { + this.negotiationCriteria[section][criteria] = event.target.files[0] + }, showNotification(variant, header, body) { this.notificationVariant = variant this.notificationHeader = header diff --git a/src/config/consts.js b/src/config/consts.js index 0aa83c8..907cc9a 100644 --- a/src/config/consts.js +++ b/src/config/consts.js @@ -12,4 +12,4 @@ const MESSAGE_STATUS = { } -export { dateFormat, ROLES, MESSAGE_STATUS } \ No newline at end of file +export { MESSAGE_STATUS, ROLES, dateFormat } \ No newline at end of file diff --git a/src/main.js b/src/main.js index e93ec6d..e297429 100644 --- a/src/main.js +++ b/src/main.js @@ -4,7 +4,7 @@ import router from "./router" import store from "./store" import { sync } from "vuex-router-sync" import { library } from "@fortawesome/fontawesome-svg-core" -import { faPencil, faSpinner, faTrash } from "@fortawesome/free-solid-svg-icons" +import { faDownload, faPencil, faSpinner, faTrash } from "@fortawesome/free-solid-svg-icons" import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome" import "bootstrap/dist/css/bootstrap.css" import "bootstrap-vue-next/dist/bootstrap-vue-next.css" @@ -13,6 +13,7 @@ import "bootstrap" library.add(faSpinner) library.add(faPencil) library.add(faTrash) +library.add(faDownload) const app = createApp(App) diff --git a/src/store/actions.js b/src/store/actions.js index 7a36b62..d694a16 100644 --- a/src/store/actions.js +++ b/src/store/actions.js @@ -1,11 +1,12 @@ -import axios from "axios" import { ROLES } from "@/config/consts" +import axios from "axios" let BASE_API_PATH = "/api/v3" const ACCESS_CRITERIA_PATH = `${BASE_API_PATH}/access-criteria/` const REQUESTS_PATH = `${BASE_API_PATH}/requests` const NEGOTIATION_PATH = `${BASE_API_PATH}/negotiations` const USER_PATH = `${BASE_API_PATH}/users/roles` +const ATTACHMENTS_PATH = `${BASE_API_PATH}/attachments` function getBearerHeaders(token) { return { @@ -34,7 +35,7 @@ export default { }) }, retrieveAccessCriteriaByResourceId({ state, commit }, { resourceId }) { - return axios.get(`${ACCESS_CRITERIA_PATH}`, {headers : getBearerHeaders(state.oidc.access_token), params : {resourceId : resourceId}}) + return axios.get(`${ACCESS_CRITERIA_PATH}`, {headers: getBearerHeaders(state.oidc.access_token), params: {resourceId: resourceId}}) .then((response) => { return response.data }) @@ -44,17 +45,41 @@ export default { }) }, - createNegotiation({ state }, { data }) { - return axios.post(NEGOTIATION_PATH, data, {headers : getBearerHeaders(state.oidc.access_token)}) + async createNegotiation({ state, commit }, { data }) { + data.attachments = [] + for (const [sectionName, criteriaList] of Object.entries(data.payload)) { + for (const [criteriaName, criteriaValue] of Object.entries(criteriaList)) { + if (criteriaValue instanceof File) { + const formData = new FormData() + formData.append("file", criteriaValue) + const uploadFileHeaders = { headers: getBearerHeaders(state.oidc.access_token) } + + uploadFileHeaders["Content-type"] = "multipart/form-data" + + const attachmentsIds = await axios.post("/api/v3/attachments", formData, uploadFileHeaders) + .then((response) => { + return response.data + }) + .catch(() => { + commit("setNotification", "There was an error saving the attachment") + return null + }) + data.payload[sectionName][criteriaName] = attachmentsIds + data.attachments.push(attachmentsIds) + } + } + } + return axios.post(NEGOTIATION_PATH, data, {headers: getBearerHeaders(state.oidc.access_token)}) .then((response) => { return response.data.id }) .catch(() => { - return null + commit("setNotification", "There was an error saving the Negotiation") }) + }, retrieveNegotiationsByRole({ state, commit }, { userRole }) { - return axios.get(`${NEGOTIATION_PATH}`, {headers : getBearerHeaders(state.oidc.access_token), params : {userRole : userRole}}) + return axios.get(`${NEGOTIATION_PATH}`, {headers: getBearerHeaders(state.oidc.access_token), params: {userRole: userRole}}) .then((response) => { return response.data }) @@ -64,7 +89,7 @@ export default { }) }, updateNegotiationStatus({ state, commit }, { negotiationId , event }) { - return axios.put(`${NEGOTIATION_PATH}/${negotiationId}/lifecycle/${event}`, {}, {headers : getBearerHeaders(state.oidc.access_token)}) + return axios.put(`${NEGOTIATION_PATH}/${negotiationId}/lifecycle/${event}`, {}, {headers: getBearerHeaders(state.oidc.access_token)}) .then((response) => { commit("setNotification", `Negotiation updated correctly with data ${response.data.id}`) return response.data @@ -75,7 +100,7 @@ export default { }) }, retrievePossibleEvents({ state, commit }, { negotiationId }) { - return axios.get(`${NEGOTIATION_PATH}/${negotiationId}/lifecycle`, {headers : getBearerHeaders(state.oidc.access_token)}) + return axios.get(`${NEGOTIATION_PATH}/${negotiationId}/lifecycle`, {headers: getBearerHeaders(state.oidc.access_token)}) .then((response) => { return response.data }) @@ -84,7 +109,7 @@ export default { }) }, retrievePossibleEventsForResource({ state, commit }, { negotiationId, resourceId }) { - return axios.get(`${NEGOTIATION_PATH}/${negotiationId}/resources/${resourceId}/lifecycle`, {headers : getBearerHeaders(state.oidc.access_token)}) + return axios.get(`${NEGOTIATION_PATH}/${negotiationId}/resources/${resourceId}/lifecycle`, {headers: getBearerHeaders(state.oidc.access_token)}) .then((response) => { return response.data }) @@ -93,7 +118,7 @@ export default { }) }, updateResourceStatus({ state, commit }, { negotiationId , resourceId, event }) { - return axios.put(`${NEGOTIATION_PATH}/${negotiationId}/resources/${resourceId}/lifecycle/${event}`, {}, {headers : getBearerHeaders(state.oidc.access_token)}) + return axios.put(`${NEGOTIATION_PATH}/${negotiationId}/resources/${resourceId}/lifecycle/${event}`, {}, {headers: getBearerHeaders(state.oidc.access_token)}) .then((response) => { commit("setNotification", `Negotiation updated correctly with data ${response.data.id}`) return response.data @@ -103,8 +128,8 @@ export default { return null }) }, - retrieveNegotiationById({ state, commit }, { negotiationId }) { - return axios.get(`${NEGOTIATION_PATH}/${negotiationId}`, {headers : getBearerHeaders(state.oidc.access_token)}) + async retrieveNegotiationById({ state, commit }, { negotiationId }) { + return axios.get(`${NEGOTIATION_PATH}/${negotiationId}`, {headers: getBearerHeaders(state.oidc.access_token)}) .then((response) => { return response.data }) @@ -114,8 +139,8 @@ export default { }, retrievePostsByNegotiationId({ state, commit }, { negotiationId, type, resourceId }) { let url = `${NEGOTIATION_PATH}/${negotiationId}/posts` - let params = resourceId ? {type: type, resource: resourceId} : {type : type} - return axios.get(url, {headers : getBearerHeaders(state.oidc.access_token), params: params}) + let params = resourceId ? {type: type, resource: resourceId} : {type: type} + return axios.get(url, {headers: getBearerHeaders(state.oidc.access_token), params: params}) .then((response) => { return response.data }) @@ -124,7 +149,7 @@ export default { }) }, addMessageToNegotiation({ state, commit }, { data }) { - return axios.post(`${NEGOTIATION_PATH}/${data.negotiationId}/posts`, data, {headers : getBearerHeaders(state.oidc.access_token)}) + return axios.post(`${NEGOTIATION_PATH}/${data.negotiationId}/posts`, data, {headers: getBearerHeaders(state.oidc.access_token)}) .then((response) => { return response.data }) @@ -133,7 +158,7 @@ export default { }) }, markMessageAsRead({ state }, { data }) { - return axios.put(`${NEGOTIATION_PATH}/${data.negotiationId}/posts/${data.postId}`, data, {headers : getBearerHeaders(state.oidc.access_token)}) + return axios.put(`${NEGOTIATION_PATH}/${data.negotiationId}/posts/${data.postId}`, data, {headers: getBearerHeaders(state.oidc.access_token)}) .then((response) => { return response.data.id }) @@ -144,7 +169,7 @@ export default { getUnreadMessagesByRole({ state }, { data }) { //the role shoud be complementary in relation of the one from the user let complementaryRole = data.Rolename == ROLES.RESEARCHER ? ROLES.REPRESENTATIVE : ROLES.RESEARCHER - return axios.get(`${NEGOTIATION_PATH}/${data.negotiationId}/${complementaryRole}/posts`, {headers : getBearerHeaders(state.oidc.access_token)}) + return axios.get(`${NEGOTIATION_PATH}/${data.negotiationId}/${complementaryRole}/posts`, {headers: getBearerHeaders(state.oidc.access_token)}) .then((response) => { return response.data }) @@ -153,13 +178,28 @@ export default { }) }, retrieveUserRoles({ state, commit }) { - return axios.get(USER_PATH, {headers : getBearerHeaders(state.oidc.access_token)}) + return axios.get(USER_PATH, {headers: getBearerHeaders(state.oidc.access_token)}) .then((response) => { return response.data }) .catch(() => { commit("setNotification", "Error sending message") }) - + }, + downloadAttachment({ state }, { id, name }) { + axios.get(`${ATTACHMENTS_PATH}/${id}`, { headers: getBearerHeaders(state.oidc.access_token), responseType: "blob" }) + .then((response) => { + const href = window.URL.createObjectURL(response.data) + + const anchorElement = document.createElement("a") + anchorElement.href = href + anchorElement.download = name + + document.body.appendChild(anchorElement) + anchorElement.click() + + document.body.removeChild(anchorElement) + window.URL.revokeObjectURL(href) + }) } } \ No newline at end of file diff --git a/src/views/NegotiationPage.vue b/src/views/NegotiationPage.vue index 44d0b7f..c158e0d 100644 --- a/src/views/NegotiationPage.vue +++ b/src/views/NegotiationPage.vue @@ -46,21 +46,33 @@
{{ key.toUpperCase() }}
- {{ subelement }} + + {{ subelement.name }} + + + + {{ subelement }} +
RESOURCE STATUS @@ -78,13 +90,9 @@
@@ -155,7 +159,7 @@