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

fixed smaller bugs

parent fa21064a
Branches
Tags
2 merge requests!81New stable release,!80Multiple features connected with user management and ownership of databases
...@@ -36,7 +36,7 @@ def create_user(username): ...@@ -36,7 +36,7 @@ def create_user(username):
"password": username, "password": username,
"email": username + "@gmail.com" "email": username + "@gmail.com"
}) })
print("created user") print("created user with id %d" % response.id)
return response return response
...@@ -45,7 +45,7 @@ def auth_user(username): ...@@ -45,7 +45,7 @@ def auth_user(username):
"username": username, "username": username,
"password": username "password": username
}) })
print("authenticated user") print("authenticated user with id %d" % response.id)
token = response.token token = response.token
container.api_client.default_headers = {"Authorization": "Bearer " + token} container.api_client.default_headers = {"Authorization": "Bearer " + token}
database.api_client.default_headers = {"Authorization": "Bearer " + token} database.api_client.default_headers = {"Authorization": "Bearer " + token}
...@@ -64,7 +64,7 @@ def create_container(): ...@@ -64,7 +64,7 @@ def create_container():
"repository": "mariadb", "repository": "mariadb",
"tag": "10.5" "tag": "10.5"
}) })
print("created container") print("created container with id %d" % response.id)
return response return response
...@@ -72,8 +72,9 @@ def start_container(container_id): ...@@ -72,8 +72,9 @@ def start_container(container_id):
response = container.modify({ response = container.modify({
"action": "start" "action": "start"
}, container_id) }, container_id)
print("... starting")
time.sleep(5) time.sleep(5)
print("started container") print("started container with id %d" % response.id)
return response return response
...@@ -83,7 +84,7 @@ def create_database(container_id, is_public=True): ...@@ -83,7 +84,7 @@ def create_database(container_id, is_public=True):
"description": "Hourly measurements in Zürich, Switzerland", "description": "Hourly measurements in Zürich, Switzerland",
"is_public": is_public "is_public": is_public
}, container_id) }, container_id)
print("created database") print("created database with id %d" % response.id)
return response return response
...@@ -99,7 +100,7 @@ def update_database(container_id, database_id, is_public=True): ...@@ -99,7 +100,7 @@ def update_database(container_id, database_id, is_public=True):
"is_public": is_public, "is_public": is_public,
"publication": "2022-07-19" "publication": "2022-07-19"
}, container_id, database_id) }, container_id, database_id)
print("updated database") print("updated database with id %d" % response.id)
return response return response
...@@ -154,13 +155,13 @@ def create_table(container_id, database_id, columns=None): ...@@ -154,13 +155,13 @@ def create_table(container_id, database_id, columns=None):
"description": "Airquality in Zürich, Switzerland", "description": "Airquality in Zürich, Switzerland",
"columns": columns "columns": columns
}, container_id, database_id) }, container_id, database_id)
print("created table") print("created table with id %d" % response.id)
return response return response
def find_table(container_id, database_id, table_id): def find_table(container_id, database_id, table_id):
response = table.find_by_id(container_id, database_id, table_id) response = table.find_by_id(container_id, database_id, table_id)
print("found table") print("found table with id %d" % response.id)
return response return response
...@@ -172,7 +173,7 @@ def fill_table(container_id, database_id, table_id): ...@@ -172,7 +173,7 @@ def fill_table(container_id, database_id, table_id):
"quote": "\"", "quote": "\"",
"skip_lines": 1 "skip_lines": 1
}, container_id, database_id, table_id) }, container_id, database_id, table_id)
print("filled table") print("filled table with id %d" % table_id)
return response return response
...@@ -181,7 +182,7 @@ def create_query(container_id, database_id, statement, page=0, size=3): ...@@ -181,7 +182,7 @@ def create_query(container_id, database_id, statement, page=0, size=3):
response = query.execute({ response = query.execute({
"statement": statement "statement": statement
}, container_id, database_id, page=page, size=size) }, container_id, database_id, page=page, size=size)
print("executed query") print("executed query with id %d" % response.id)
return response return response
except api_query.rest.ApiException as e: except api_query.rest.ApiException as e:
print(e) print(e)
...@@ -209,7 +210,7 @@ def create_identifier(container_id, database_id, query_id, visibility="everyone" ...@@ -209,7 +210,7 @@ def create_identifier(container_id, database_id, query_id, visibility="everyone"
"relation": "IsCitedBy" "relation": "IsCitedBy"
}] }]
}, token, container_id, database_id) }, token, container_id, database_id)
print("created identifier") print("created identifier with id %d" % response.id)
return response return response
...@@ -271,3 +272,24 @@ if __name__ == '__main__': ...@@ -271,3 +272,24 @@ if __name__ == '__main__':
"primary_key": True, "primary_key": True,
"null_allowed": False, "null_allowed": False,
}]) }])
#
# create 1 user and 1 container and issue queries to own and foreign database
#
create_user("test2")
auth_user("test2")
# container 4
cid = create_container().id
start_container(cid)
dbid = create_database(cid).id
update_database(cid, dbid)
tid = create_table(cid, dbid).id
tname = find_table(cid, dbid, tid).internal_name
fill_table(cid, dbid, tid)
create_query(cid, dbid, "select `id` from `" + tname + "`")
create_query(cid, dbid, "select `date` from `" + tname + "`")
qid = create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "`").id
create_identifier(cid, dbid, qid)
# container 1
tname = find_table(1, 1, 1).internal_name
qid = create_query(1, 1, "select `id` from `" + tname + "`").id
create_identifier(1, 1, qid)
...@@ -79,6 +79,10 @@ ...@@ -79,6 +79,10 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId> <artifactId>spring-boot-starter-security</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.security</groupId> <groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId> <artifactId>spring-security-test</artifactId>
... ...
......
...@@ -65,13 +65,13 @@ public class QueryEndpoint extends AbstractEndpoint { ...@@ -65,13 +65,13 @@ public class QueryEndpoint extends AbstractEndpoint {
@PutMapping("/{queryId}") @PutMapping("/{queryId}")
@Transactional(readOnly = true) @Transactional(readOnly = true)
@Operation(summary = "Re-execute some query") @Operation(summary = "Re-execute some query", security = @SecurityRequirement(name = "bearerAuth"))
public ResponseEntity<QueryResultDto> reExecute(@NotNull @PathVariable("id") Long containerId, public ResponseEntity<QueryResultDto> reExecute(@NotNull @PathVariable("id") Long containerId,
@NotNull @PathVariable("databaseId") Long databaseId, @NotNull @PathVariable("databaseId") Long databaseId,
@NotNull @PathVariable("queryId") Long queryId, @NotNull @PathVariable("queryId") Long queryId,
@RequestParam(value = "page", required = false) Long page, @RequestParam(value = "page", required = false) Long page,
@RequestParam(value = "size", required = false) Long size, @RequestParam(value = "size", required = false) Long size,
@NotNull Principal principal) Principal principal)
throws QueryStoreException, QueryNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, throws QueryStoreException, QueryNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
TableNotFoundException, QueryMalformedException, ContainerNotFoundException, TableMalformedException, TableNotFoundException, QueryMalformedException, ContainerNotFoundException, TableMalformedException,
ColumnParseException, NotAllowedException, DatabaseConnectionException { ColumnParseException, NotAllowedException, DatabaseConnectionException {
...@@ -92,7 +92,7 @@ public class QueryEndpoint extends AbstractEndpoint { ...@@ -92,7 +92,7 @@ public class QueryEndpoint extends AbstractEndpoint {
public ResponseEntity<InputStreamResource> export(@NotNull @PathVariable("id") Long containerId, public ResponseEntity<InputStreamResource> export(@NotNull @PathVariable("id") Long containerId,
@NotNull @PathVariable("databaseId") Long databaseId, @NotNull @PathVariable("databaseId") Long databaseId,
@NotNull @PathVariable("queryId") Long queryId, @NotNull @PathVariable("queryId") Long queryId,
@NotNull Principal principal) Principal principal)
throws QueryStoreException, QueryNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, throws QueryStoreException, QueryNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
ContainerNotFoundException, TableMalformedException, FileStorageException, NotAllowedException, ContainerNotFoundException, TableMalformedException, FileStorageException, NotAllowedException,
QueryMalformedException, DatabaseConnectionException { QueryMalformedException, DatabaseConnectionException {
... ...
......
...@@ -28,7 +28,7 @@ server.port: 9093 ...@@ -28,7 +28,7 @@ server.port: 9093
logging: logging:
pattern.console: "%d %highlight(%-5level) %msg%n" pattern.console: "%d %highlight(%-5level) %msg%n"
level: level:
root: warn root: debug
at.tuwien.: trace at.tuwien.: trace
at.tuwien.mapper.: trace at.tuwien.mapper.: trace
at.tuwien.service.: trace at.tuwien.service.: trace
... ...
......
...@@ -70,6 +70,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { ...@@ -70,6 +70,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.antMatchers(HttpMethod.GET, "/api/container/**/database/**/table/**/history/**").permitAll() .antMatchers(HttpMethod.GET, "/api/container/**/database/**/table/**/history/**").permitAll()
.antMatchers(HttpMethod.GET, "/api/container/**/database/**/table/**/export/**").permitAll() .antMatchers(HttpMethod.GET, "/api/container/**/database/**/table/**/export/**").permitAll()
.antMatchers(HttpMethod.GET, "/api/container/**/database/**/query/**").permitAll() .antMatchers(HttpMethod.GET, "/api/container/**/database/**/query/**").permitAll()
.antMatchers(HttpMethod.GET, "/api/container/**/database/**/query/**/export").permitAll()
.antMatchers(HttpMethod.PUT, "/api/container/**/database/**/query/**").permitAll()
.antMatchers("/v3/api-docs.yaml", .antMatchers("/v3/api-docs.yaml",
"/v3/api-docs/**", "/v3/api-docs/**",
"/swagger-ui/**", "/swagger-ui/**",
... ...
......
<template> <template>
<div> <div>
<v-progress-linear v-if="loading" :color="loadingColor" /> <v-toolbar v-if="cached_database" flat>
<v-toolbar v-if="db" flat>
<v-toolbar-title> <v-toolbar-title>
{{ db.name }} <span>{{ cached_database.name }}</span>
<v-icon v-if="!cached_database.is_public" color="primary" class="mb-1" right>mdi-lock-outline</v-icon>
<v-icon v-if="cached_database.is_public" class="mb-1" right>mdi-lock-open-outline</v-icon>
</v-toolbar-title> </v-toolbar-title>
<v-spacer /> <v-spacer />
<v-toolbar-title> <v-toolbar-title>
...@@ -40,11 +41,15 @@ export default { ...@@ -40,11 +41,15 @@ export default {
return { return {
tab: null, tab: null,
loading: false, loading: false,
error: false error: false,
database: {
id: null,
is_public: null
}
} }
}, },
computed: { computed: {
db () { cached_database () {
return this.$store.state.db return this.$store.state.db
}, },
databaseId () { databaseId () {
...@@ -65,17 +70,28 @@ export default { ...@@ -65,17 +70,28 @@ export default {
} }
} }
}, },
mounted () { watch: {
this.init() $route () {
if (this.database.id !== this.$route.params.database_id) {
this.loadDatabase()
}
}
}, },
methods: { mounted () {
async init () { if (this.database.id) {
if (this.db != null) { return
}
if (this.cached_database && this.cached_database.id === this.$route.params.database_id) {
return return
} }
this.loadDatabase()
},
methods: {
async loadDatabase () {
try { try {
this.loading = true this.loading = true
const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}`, this.config) const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}`, this.config)
this.database = res.data
console.debug('database', res.data) console.debug('database', res.data)
this.$store.commit('SET_DATABASE', res.data) this.$store.commit('SET_DATABASE', res.data)
this.loading = false this.loading = false
... ...
......
...@@ -117,6 +117,9 @@ export default { ...@@ -117,6 +117,9 @@ export default {
}, },
executionUTC () { executionUTC () {
return formatTimestampUTCLabel(this.queryDetails.execution) return formatTimestampUTCLabel(this.queryDetails.execution)
},
creator () {
return this.queryDetails.creator
} }
}, },
mounted () { mounted () {
... ...
......
...@@ -207,7 +207,7 @@ ...@@ -207,7 +207,7 @@
</v-list-item-title> </v-list-item-title>
<v-list-item-content> <v-list-item-content>
<v-alert <v-alert
v-if="!loadingQuery && erroneous" v-if="!error && !loadingQuery && erroneous"
border="left" border="left"
color="error"> color="error">
This query failed to execute and did not produce a subset. This query failed to execute and did not produce a subset.
...@@ -425,10 +425,7 @@ export default { ...@@ -425,10 +425,7 @@ export default {
async download () { async download () {
this.downloadLoading = true this.downloadLoading = true
try { try {
const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query/${this.$route.params.query_id}/export`, { const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query/${this.$route.params.query_id}/export`, this.config)
headers: { Authorization: `Bearer ${this.token}` },
responseType: 'text'
})
console.debug('export query result', res) console.debug('export query result', res)
const url = window.URL.createObjectURL(new Blob([res.data])) const url = window.URL.createObjectURL(new Blob([res.data]))
const link = document.createElement('a') const link = document.createElement('a')
... ...
......
...@@ -18,43 +18,43 @@ ...@@ -18,43 +18,43 @@
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Visibility</th>
<th>Engine</th> <th>Engine</th>
<th>Creator</th> <th>Creator</th>
<th>Visibility</th>
<th>Created</th> <th>Created</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody
<tr v-if="containers.length === 0" aria-readonly="true"> v-if="!loading">
<tr v-if="databases.length === 0" aria-readonly="true">
<td colspan="5"> <td colspan="5">
<span v-if="!loading">(no databases)</span> <span>(no databases)</span>
</td> </td>
</tr> </tr>
<tr <tr
v-for="item in containers" v-for="item in databases"
:key="item.id" :key="item.id"
class="database" class="database"
@click="loadDatabase(item)"> @click="loadDatabase(item)">
<td>{{ item.name }}</td>
<td> <td>
<v-skeleton-loader v-if="!item.database" type="text" width="50" class="mt-1" /> <span>{{ item.name }}</span>
<span v-if="item.database">
<span v-if="item.database.is_public">Public</span>
<span v-if="!item.database.is_public">Private <v-icon right>mdi-eye-off</v-icon></span>
</span>
</td> </td>
<td> <td>
<span v-if="item.database">{{ item.database.engine }}</span> <span>{{ item.engine }}</span>
<v-skeleton-loader v-if="!item.database" type="text" width="100" class="mt-1" />
</td> </td>
<td> <td>
<span v-if="item.database">{{ formatCreator(item.database.creator) }}</span> <span>{{ formatCreator(item.creator) }}</span>
<v-skeleton-loader v-if="!item.database" type="text" width="100" class="mt-1" /> <sup>
<sup v-if="item.database"> <v-icon v-if="item.creator.email_verified" small color="primary">mdi-check-decagram</v-icon>
<v-icon v-if="item.database.creator.email_verified" small color="primary">mdi-check-decagram</v-icon>
</sup> </sup>
</td> </td>
<td>{{ createdUTC(item.created) }}</td> <td>
<v-icon v-if="!item.is_public" color="primary" class="private-icon" right>mdi-lock-outline</v-icon>
<v-icon v-if="item.is_public" class="private-icon" right>mdi-lock-open-outline</v-icon>
</td>
<td>
{{ createdUTC(item.created) }}
</td>
</tr> </tr>
</tbody> </tbody>
</template> </template>
...@@ -81,12 +81,12 @@ export default { ...@@ -81,12 +81,12 @@ export default {
data () { data () {
return { return {
createDbDialog: false, createDbDialog: false,
databases: [],
containers: [], containers: [],
searchQuery: null, searchQuery: null,
items: [ items: [
{ text: 'Databases', to: '/container', activeClass: '' } { text: 'Databases', to: '/container', activeClass: '' }
], ],
loadingContainers: false,
loading: false, loading: false,
error: false, error: false,
iconSelect: mdiDatabaseArrowRightOutline iconSelect: mdiDatabaseArrowRightOutline
...@@ -122,7 +122,7 @@ export default { ...@@ -122,7 +122,7 @@ export default {
async loadContainers () { async loadContainers () {
this.createDbDialog = false this.createDbDialog = false
try { try {
this.loadingContainers = true this.loading = true
const res = await this.$axios.get('/api/container/') const res = await this.$axios.get('/api/container/')
this.containers = res.data this.containers = res.data
console.debug('containers', this.containers) console.debug('containers', this.containers)
...@@ -130,20 +130,20 @@ export default { ...@@ -130,20 +130,20 @@ export default {
} catch (err) { } catch (err) {
console.error('containers', err) console.error('containers', err)
this.error = true this.error = true
this.loading = false
} }
this.loadingContainers = false
}, },
async loadDatabases () { async loadDatabases () {
if (this.containers.length === 0) { if (this.containers.length === 0) {
return return
} }
const containers = [] this.loading = true
for (const container of this.containers) { for (const container of this.containers) {
try { try {
const res = await this.$axios.get(`/api/container/${container.id}/database`, this.config) const res = await this.$axios.get(`/api/container/${container.id}/database`, this.config)
for (const database of res.data) { for (const info of res.data) {
container.database = database info.container_id = container.id
containers.push(container) this.databases.push(info)
} }
} catch (err) { } catch (err) {
if (err.response === undefined || err.response.status === undefined || err.response.status !== 401) { if (err.response === undefined || err.response.status === undefined || err.response.status !== 401) {
...@@ -151,18 +151,14 @@ export default { ...@@ -151,18 +151,14 @@ export default {
} }
} }
} }
this.containers = containers this.loading = false
console.debug('databases loaded', this.containers) console.debug('databases', this.databases)
}, },
createdUTC (str) { createdUTC (str) {
return formatTimestampUTCLabel(str) return formatTimestampUTCLabel(str)
}, },
loadDatabase (container) { loadDatabase (database) {
if (!container.id || !container.database) { this.$router.push(`/container/${database.container_id}/database/${database.id}/info`)
console.error('container id', container.id, 'or database id missing')
return
}
this.$router.push(`/container/${container.id}/database/${container.database.id}/info`)
} }
} }
} }
...@@ -184,4 +180,8 @@ export default { ...@@ -184,4 +180,8 @@ export default {
.v-progress-circular { .v-progress-circular {
margin-left: 8px; margin-left: 8px;
} }
.private-icon {
flex: 0 !important;
margin-right: 16px;
}
</style> </style>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment