Skip to content
Snippets Groups Projects
Unverified Commit e1569726 authored by Martin Weise's avatar Martin Weise
Browse files

WIP

parent b8865342
Branches
Tags
2 merge requests!163Relase 1.3.0,!161Resolve "Frontend bugs"
Showing
with 480 additions and 50 deletions
......@@ -5,13 +5,14 @@ MAINTAINER Martin Weise <martin.weise@tuwien.ac.at>
# Enable health and metrics support
ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
ENV KC_FEATURES=update-email
# Configure a database vendor
ENV KC_DB=mariadb
WORKDIR /opt/keycloak
COPY ./server.keystore ./conf/server.keystore
RUN /opt/keycloak/bin/kc.sh build
###### SECOND STAGE ######
......
......@@ -55,6 +55,17 @@
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "9bb4a8dc-28e0-4645-b62f-cc94425f0cb0",
"name" : "default-maintenance-handling",
"description" : "${default-maintenance-handling}",
"composite" : true,
"composites" : {
"realm" : [ "create-maintenance-message", "find-maintenance-message", "update-maintenance-message", "delete-maintenance-message", "list-maintenance-messages" ]
},
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "5136d7a3-e3f0-4585-bacd-15cb8a56095c",
"name" : "escalated-container-handling",
......@@ -198,6 +209,14 @@
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "f4116230-8642-4bb7-bbc8-db9c5c07b558",
"name" : "create-maintenance-message",
"description" : "${create-maintenance-message}",
"composite" : false,
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "973f0999-cc70-4b28-9f43-979c470bea8e",
"name" : "default-data-steward-roles",
......@@ -249,6 +268,14 @@
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "272a79a7-e282-4261-8f7d-5d5d1364243a",
"name" : "update-maintenance-message",
"description" : "${update-maintenance-message}",
"composite" : false,
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "64c16bfb-2015-48ad-a23f-637ff24419cb",
"name" : "default-query-handling",
......@@ -268,6 +295,14 @@
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "c047d521-cec3-4444-86c4-aef098489b7b",
"name" : "delete-maintenance-message",
"description" : "${delete-maintenance-message}",
"composite" : false,
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "e14ab76b-1c24-484d-ae2d-478b8457edea",
"name" : "list-licenses",
......@@ -435,7 +470,7 @@
"description" : "${default-developer-roles}",
"composite" : true,
"composites" : {
"realm" : [ "escalated-query-handling", "default-table-handling", "escalated-database-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "escalated-container-handling", "escalated-table-handling", "default-identifier-handling" ]
"realm" : [ "escalated-query-handling", "default-table-handling", "escalated-database-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-maintenance-handling", "escalated-container-handling", "escalated-table-handling", "default-identifier-handling" ]
},
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
......@@ -504,6 +539,14 @@
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "d6e38368-b40f-423b-82e4-e8aa595237c9",
"name" : "find-maintenance-message",
"description" : "${find-maintenance-message}",
"composite" : false,
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "fd1cc463-3e67-49d9-81b8-2cd90c1daa9c",
"name" : "check-database-access",
......@@ -539,6 +582,14 @@
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "09f7bdb0-296f-46c8-a3a3-8f9254fb17e4",
"name" : "list-maintenance-messages",
"description" : "${list-maintenance-messages}",
"composite" : false,
"clientRole" : false,
"containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0",
"attributes" : { }
}, {
"id" : "fe3bc45c-61c2-4ece-bcaf-d410dc7de501",
"name" : "update-database-access",
......@@ -909,7 +960,7 @@
"otpPolicyLookAheadWindow" : 1,
"otpPolicyPeriod" : 30,
"otpPolicyCodeReusable" : false,
"otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName" ],
"otpSupportedApplications" : [ "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName", "totpAppFreeOTPName" ],
"webAuthnPolicyRpEntityName" : "keycloak",
"webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
"webAuthnPolicyRpId" : "",
......@@ -1932,7 +1983,7 @@
"subType" : "authenticated",
"subComponents" : { },
"config" : {
"allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-attribute-mapper" ]
"allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper" ]
}
}, {
"id" : "3ab11d74-5e76-408a-b85a-26bf8950f979",
......@@ -1941,7 +1992,7 @@
"subType" : "anonymous",
"subComponents" : { },
"config" : {
"allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper" ]
"allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-property-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper" ]
}
} ],
"org.keycloak.keys.KeyProvider" : [ {
......@@ -1993,7 +2044,7 @@
"internationalizationEnabled" : false,
"supportedLocales" : [ ],
"authenticationFlows" : [ {
"id" : "7e7d6810-5b6c-4ec6-865c-5f0b62ec56d7",
"id" : "a50c392e-a870-484c-b7c4-7c85e886ee46",
"alias" : "Account verification options",
"description" : "Method with which to verity the existing account",
"providerId" : "basic-flow",
......@@ -2015,7 +2066,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "6d972ab3-0618-4971-b44a-0fc0d11c7280",
"id" : "3f384243-bf93-4535-8811-b23526f12963",
"alias" : "Authentication Options",
"description" : "Authentication options.",
"providerId" : "basic-flow",
......@@ -2044,7 +2095,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "821a14e0-ef26-4b07-b716-fa34393eda56",
"id" : "478c7d4f-86f2-42eb-91db-4bc03e20e416",
"alias" : "Browser - Conditional OTP",
"description" : "Flow to determine if the OTP is required for the authentication",
"providerId" : "basic-flow",
......@@ -2066,7 +2117,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "e70eadbd-4c39-4cfd-86ac-e50acc753b1b",
"id" : "cca43646-a74e-4439-b029-3c0a11cd3693",
"alias" : "Direct Grant - Conditional OTP",
"description" : "Flow to determine if the OTP is required for the authentication",
"providerId" : "basic-flow",
......@@ -2088,7 +2139,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "4e35af97-acf4-4ca8-bc81-0477c1adfb6d",
"id" : "815189fe-ef5f-4865-be03-1e4b5dd9eafe",
"alias" : "First broker login - Conditional OTP",
"description" : "Flow to determine if the OTP is required for the authentication",
"providerId" : "basic-flow",
......@@ -2110,7 +2161,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "2e0bd063-274a-4aab-a5f0-038a0bca5b98",
"id" : "b72709d3-246d-4057-a82f-1a6e721bdd0c",
"alias" : "Handle Existing Account",
"description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
"providerId" : "basic-flow",
......@@ -2132,7 +2183,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "6a20fab2-44bb-4451-b29a-6fb7e14a52ce",
"id" : "191c4793-7fdd-449a-8218-70d047d882b7",
"alias" : "Reset - Conditional OTP",
"description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
"providerId" : "basic-flow",
......@@ -2154,7 +2205,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "159d7398-74a7-4f60-a3fd-eb2df46f5ce7",
"id" : "afd9a108-753a-4012-a65f-69d149d8313a",
"alias" : "User creation or linking",
"description" : "Flow for the existing/non-existing user alternatives",
"providerId" : "basic-flow",
......@@ -2177,7 +2228,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "85a66c55-4665-4ba0-bec9-7254eb8e5895",
"id" : "95c1347f-8248-4506-8ac7-77da64331658",
"alias" : "Verify Existing Account by Re-authentication",
"description" : "Reauthentication of existing account",
"providerId" : "basic-flow",
......@@ -2199,7 +2250,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "c002e6da-2397-4fae-8d48-1eec3719ca15",
"id" : "00aa962b-69e7-4032-99d6-33d2e15689bf",
"alias" : "browser",
"description" : "browser based authentication",
"providerId" : "basic-flow",
......@@ -2235,7 +2286,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "a03631cf-2fea-4a12-a35c-8137023503bd",
"id" : "b7efe33a-b00a-4830-b362-739101e1a437",
"alias" : "clients",
"description" : "Base authentication for clients",
"providerId" : "client-flow",
......@@ -2271,7 +2322,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "a89940e4-bf4d-4a04-8fdf-dcf775336b20",
"id" : "39a89fb2-74b0-44bb-877c-a2f75044f5e1",
"alias" : "direct grant",
"description" : "OpenID Connect Resource Owner Grant",
"providerId" : "basic-flow",
......@@ -2300,7 +2351,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "2dc2582b-be6f-4d9a-b545-b2c0e79a3581",
"id" : "c0b9af60-9bb2-42e2-815d-c03144b4773c",
"alias" : "docker auth",
"description" : "Used by Docker clients to authenticate against the IDP",
"providerId" : "basic-flow",
......@@ -2315,7 +2366,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "09e56692-226f-4384-85e0-e33463cdb226",
"id" : "50e548b3-60a1-4511-838a-894462d7437a",
"alias" : "first broker login",
"description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
"providerId" : "basic-flow",
......@@ -2338,7 +2389,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "1439c900-92e0-4230-a1a7-ae82c3b8ddc9",
"id" : "260eb8b4-8889-41e4-b3d4-ce8adf15474c",
"alias" : "forms",
"description" : "Username, password, otp and other auth forms.",
"providerId" : "basic-flow",
......@@ -2360,7 +2411,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "4cc3bb1b-e85d-447e-b50e-1afbe107bafe",
"id" : "d7db5234-08e2-44ed-8708-5f4e906fe8a5",
"alias" : "http challenge",
"description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
"providerId" : "basic-flow",
......@@ -2382,7 +2433,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "04c49d80-30e4-4a37-b1c7-4d18c1b6a7f1",
"id" : "73ada652-053b-42f3-be1f-af907cdd3151",
"alias" : "registration",
"description" : "registration flow",
"providerId" : "basic-flow",
......@@ -2398,7 +2449,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "85abb75a-0774-4b2d-8a71-2a92b0cfb639",
"id" : "ef0d04cc-a30d-4cdc-8e62-26075e256f41",
"alias" : "registration form",
"description" : "registration form",
"providerId" : "form-flow",
......@@ -2434,7 +2485,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "948f68c1-015b-4349-a56f-6ee177d558ce",
"id" : "c6db550e-4542-4474-8e3d-955fb50b1a05",
"alias" : "reset credentials",
"description" : "Reset credentials for a user if they forgot their password or something",
"providerId" : "basic-flow",
......@@ -2470,7 +2521,7 @@
"userSetupAllowed" : false
} ]
}, {
"id" : "6046d416-4a88-4af6-b440-9fbc87fba478",
"id" : "9ba81baf-f271-44df-b712-1a58af78c27c",
"alias" : "saml ecp",
"description" : "SAML ECP Profile Authentication Flow",
"providerId" : "basic-flow",
......@@ -2486,13 +2537,13 @@
} ]
} ],
"authenticatorConfig" : [ {
"id" : "3c91aefc-127f-4722-8375-72e8434d6266",
"id" : "d70d482f-3f61-4514-918f-9634c6dc7200",
"alias" : "create unique user config",
"config" : {
"require.password.update.after.registration" : "false"
}
}, {
"id" : "1041c583-4682-44a8-b61b-9712bd4987c4",
"id" : "b5e8a2b3-a407-42f4-bc5d-c82c2c77c8d1",
"alias" : "review profile config",
"config" : {
"update.profile.on.first.login" : "missing"
......
#!/bin/bash
keytool -genkey -alias server -keyalg RSA -keypass password -storepass password -keystore server.keystore
\ No newline at end of file
File added
package at.tuwien.api.maintenance;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.*;
import lombok.extern.jackson.Jacksonized;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Jacksonized
@ToString
public class BannerMessageBriefDto {
@NotNull
private BannerMessageTypeDto type;
@NotBlank
@Schema(example = "Maintenance starts on 8am on Monday")
private String message;
@Schema(example = "https://example.com")
private String link;
@JsonProperty("link_text")
@Schema(example = "More")
private String linkText;
}
package at.tuwien.api.maintenance;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.*;
import lombok.extern.jackson.Jacksonized;
import java.time.Instant;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Jacksonized
@ToString
public class BannerMessageCreateDto {
@NotNull
private BannerMessageTypeDto type;
@NotBlank
@Schema(example = "Maintenance starts on 8am on Monday")
private String message;
@Schema(example = "https://example.com")
private String link;
@JsonProperty("link_text")
@Schema(example = "More")
private String linkText;
@JsonProperty("display_start")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
private Instant displayStart;
@JsonProperty("display_end")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
private Instant displayEnd;
}
package at.tuwien.api.maintenance;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.*;
import lombok.extern.jackson.Jacksonized;
import java.time.Instant;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Jacksonized
@ToString
public class BannerMessageDto {
@NotNull
private Long id;
@NotNull
private BannerMessageTypeDto type;
@NotBlank
@Schema(example = "Maintenance starts on 8am on Monday")
private String message;
@Schema(example = "https://example.com")
private String link;
@JsonProperty("link_text")
@Schema(example = "More")
private String linkText;
@JsonProperty("display_start")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
private Instant displayStart;
@JsonProperty("display_end")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
private Instant displayEnd;
}
package at.tuwien.api.maintenance;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
@Getter
public enum BannerMessageTypeDto {
@JsonProperty("error")
ERROR("error"),
@JsonProperty("warning")
WARNING("warning"),
@JsonProperty("info")
INFO("info");
private String name;
BannerMessageTypeDto(String name) {
this.name = name;
}
@Override
public String toString() {
return this.name;
}
}
package at.tuwien.api.maintenance;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.*;
import lombok.extern.jackson.Jacksonized;
import java.time.Instant;
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Jacksonized
@ToString
public class BannerMessageUpdateDto {
@NotNull
private BannerMessageTypeDto type;
@NotBlank
@Schema(example = "Maintenance starts on 8am on Monday")
private String message;
@Schema(example = "https://example.com")
private String link;
@JsonProperty("link_text")
@Schema(example = "More")
private String linkText;
@JsonProperty("display_start")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
private Instant displayStart;
@JsonProperty("display_end")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
private Instant displayEnd;
}
package at.tuwien.entities.maintenance;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.Instant;
@Data
@Entity
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
@Table(name = "mdb_banner_messages")
@NamedQueries({
@NamedQuery(name = "BannerMessage.findByActive", query = "select m from BannerMessage m where (m.displayStart = null and m.displayEnd = null) or (m.displayStart = null and m.displayEnd >= NOW()) or (m.displayStart <= NOW() and m.displayEnd >= NOW()) or (m.displayStart <= NOW() and m.displayEnd = null)")
})
public class BannerMessage {
@Id
@EqualsAndHashCode.Include
@GeneratedValue(generator = "messages-sequence")
@GenericGenerator(name = "messages-sequence", strategy = "increment")
@Column(updatable = false, nullable = false)
private Long id;
@Enumerated(EnumType.STRING)
@Column(nullable = false, columnDefinition = "enum('ERROR','WARNING','INFO')")
private BannerMessageType type;
@Column(nullable = false)
private String message;
@Column(columnDefinition = "TIMESTAMP")
private Instant displayStart;
@Column(columnDefinition = "TIMESTAMP")
private Instant displayEnd;
}
package at.tuwien.entities.maintenance;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
public enum BannerMessageType {
WARNING,
ERROR,
INFO;
}
\ No newline at end of file
......@@ -332,6 +332,18 @@ CREATE TABLE IF NOT EXISTS `fda`.`mdb_view`
FOREIGN KEY (vdbid) REFERENCES mdb_databases (id)
) WITH SYSTEM VERSIONING;
CREATE TABLE IF NOT EXISTS `fda`.`mdb_banner_messages`
(
id bigint NOT NULL AUTO_INCREMENT,
type ENUM ('ERROR', 'WARNING', 'INFO') NOT NULL default 'INFO',
message TEXT NOT NULL,
link TEXT NULL,
link_text VARCHAR(255) NULL,
display_start timestamp NULL,
display_end timestamp NULL,
PRIMARY KEY (id)
) WITH SYSTEM VERSIONING;
CREATE TABLE IF NOT EXISTS `fda`.`mdb_view_columns`
(
id BIGINT NOT NULL AUTO_INCREMENT,
......
......@@ -114,6 +114,12 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<!-- Authentication -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<!-- IDE -->
<dependency>
<groupId>org.projectlombok</groupId>
......
......@@ -2,7 +2,6 @@ package at.tuwien.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
......
......@@ -5,7 +5,6 @@ import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
......
import Vue from 'vue'
import api from '@/api'
class MetadataService {
findAllMessages () {
return new Promise((resolve, reject) => {
api.get('/api/maintenance/message', { headers: { Accept: 'application/json' } })
.then((response) => {
const messages = response.data
console.debug('response messages', messages)
resolve(messages)
})
.catch((error) => {
const { code, message } = error
console.error('Failed to load messages', error)
Vue.$toast.error(`[${code}] Failed to load messages: ${message}`)
reject(error)
})
})
}
createMessage (data) {
return new Promise((resolve, reject) => {
api.post('/api/maintenance/message', data, { headers: { Accept: 'application/json' } })
.then((response) => {
const messages = response.data
console.debug('response message', messages)
resolve(messages)
})
.catch((error) => {
const { code, message } = error
console.error('Failed to create message', error)
Vue.$toast.error(`[${code}] Failed to create message: ${message}`)
reject(error)
})
})
}
findMessage (id) {
return new Promise((resolve, reject) => {
api.get(`/api/maintenance/message/${id}`, { headers: { Accept: 'application/json' } })
.then((response) => {
const messages = response.data
console.debug('response message', messages)
resolve(messages)
})
.catch((error) => {
const { code, message } = error
console.error('Failed to find message', error)
Vue.$toast.error(`[${code}] Failed to find message: ${message}`)
reject(error)
})
})
}
updateMessage (id, data) {
return new Promise((resolve, reject) => {
api.put(`/api/maintenance/message/${id}`, data, { headers: { Accept: 'application/json' } })
.then((response) => {
const messages = response.data
console.debug('response message', messages)
resolve(messages)
})
.catch((error) => {
const { code, message } = error
console.error('Failed to update message', error)
Vue.$toast.error(`[${code}] Failed to update message: ${message}`)
reject(error)
})
})
}
deleteMessage (id) {
return new Promise((resolve, reject) => {
api.delete(`/api/maintenance/message/${id}`, { headers: { Accept: 'application/json' } })
.then(() => resolve())
.catch((error) => {
const { code, message } = error
console.error('Failed to delete message', error)
Vue.$toast.error(`[${code}] Failed to delete message: ${message}`)
reject(error)
})
})
}
findActiveMessages () {
return new Promise((resolve, reject) => {
api.get('/api/maintenance/message/active', { headers: { Accept: 'application/json' } })
.then((response) => {
const messages = response.data
console.debug('response messages', messages)
resolve(messages)
})
.catch((error) => {
const { code, message } = error
console.error('Failed to load active messages', error)
Vue.$toast.error(`[${code}] Failed to load active messages: ${message}`)
reject(error)
})
})
}
}
export default new MetadataService()
......@@ -55,7 +55,7 @@
<v-tab :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table`">
{{ $t('databases.toolbar.tables', { name: 'vue-i18n' }) }}
</v-tab>
<v-tab v-if="hasReadAccess" :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/query`">
<v-tab v-if="canViewQueries" :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/query`">
{{ $t('databases.toolbar.subsets', { name: 'vue-i18n' }) }}
</v-tab>
<v-tab :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/view`">
......@@ -121,6 +121,9 @@ export default {
}
return this.roles.includes('execute-query')
},
canViewQueries () {
return this.database.is_public || this.hasReadAccess
},
canCreateView () {
if (!this.user || !this.isOwner) {
return false
......
<template>
<div>
<v-progress-linear v-if="loadingContainers || loadingDatabases" :indeterminate="!error" />
<v-card v-if="!$vuetify.theme.dark && containers.list > 0" flat tile>
<v-divider class="mx-4" />
</v-card>
<v-card
v-for="(container, idx) in containers"
:key="idx"
:to="link(container)"
flat
tile>
<v-divider v-if="!$vuetify.theme.dark" class="mx-4" />
<v-divider v-if="idx !== 0" class="mx-4" />
<v-card-title v-if="!hasDatabase(container)" v-text="container.name" />
<v-card-title v-if="hasDatabase(container)">
<a :href="`/container/${container.id}/database/${container.database.id}`">{{ container.name }}</a>
......
<template>
<div>
<v-progress-linear v-if="loadingIdentifiers || loadingQueries || error" :color="loadingColor" :value="loadProgress" />
<v-card v-if="!(loadingIdentifiers || loadingQueries) && queries && queries.length === 0" flat>
<v-progress-linear v-if="loadingIdentifiers || loadingQueries || error" :color="loadingColor" :indeterminate="!error" />
<v-card v-if="!error && !(loadingIdentifiers || loadingQueries) && queries && queries.length === 0" flat tile>
<v-card-text>
(no subsets)
</v-card-text>
</v-card>
<v-card v-if="error" flat tile>
<v-card-text>
Failed to load queries: database is not reachable
</v-card-text>
</v-card>
<v-tabs-items>
<div v-if="!loadingQueries && !error">
<div v-for="(item,i) in queries" :key="i">
......@@ -77,7 +82,6 @@ export default {
return {
loadingQueries: false,
loadingIdentifiers: false,
loadProgress: 0,
error: false,
queries: [],
identifiers: []
......@@ -129,7 +133,6 @@ export default {
mounted () {
this.loadQueries()
this.loadIdentifiers()
this.simulateProgress()
},
methods: {
loadIdentifiers () {
......@@ -148,6 +151,9 @@ export default {
.then((queries) => {
this.queries = queries
})
.catch(() => {
this.error = true
})
.finally(() => {
this.loadingQueries = false
})
......@@ -181,20 +187,6 @@ export default {
return 'primary--text'
}
return null
},
simulateProgress () {
if (this.loadProgress !== 0) {
return
}
const timeout = 30 * 1000 /* ms */
const ticks = 100 /* ms */
let i = 0
setInterval(() => {
if (i++ >= timeout && !this.error) {
return
}
this.loadProgress = ((i * 100) / timeout) * 100
}, ticks)
}
}
}
......
......@@ -108,12 +108,18 @@ export default {
return UserUtils.hasWriteAccess(this.access) && this.roles.includes('insert-table-data')
},
canEditTuple () {
if (this.selection === null || this.selection.length !== 1) {
return false
}
if (!this.roles || !this.isDataTab) {
return false
}
return UserUtils.hasWriteAccess(this.access) && this.roles.includes('insert-table-data')
},
canDeleteTuple () {
if (this.selection === null || this.selection.length < 1) {
return false
}
if (!this.roles || !this.isDataTab) {
return false
}
......@@ -199,7 +205,7 @@ export default {
})
TableService.deleteTuple(this.$route.params.container_id, this.$route.params.database_id, this.$route.params.table_id, { keys: constraints })
.then(() => {
this.$toast.success(`Deleted ${this.selection.length} rows(s)`)
this.$toast.success(`Deleted ${this.selection.length} row${this.selection.length !== 1 ? 's' : ''}`)
this.$emit('modified', { success: true, action: 'delete' })
})
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment