mirror of
https://github.com/pds-nest/nest.git
synced 2024-11-23 21:44:19 +00:00
💥 Refactor some things to improve code quality
This commit is contained in:
parent
7a6e72c830
commit
bc2310f18e
11 changed files with 323 additions and 110 deletions
|
@ -11,6 +11,7 @@ module.exports = {
|
|||
config.roots = config.roots.map(root => root.replace("src", "nest_frontend"))
|
||||
config.collectCoverageFrom = config.collectCoverageFrom.map(root => root.replace("src", "nest_frontend"))
|
||||
config.testMatch = config.testMatch.map(root => root.replace("src", "nest_frontend"))
|
||||
console.debug(config)
|
||||
return config;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
// Link.react.test.js
|
||||
import React from "react"
|
||||
import "@testing-library/jest-dom/extend-expect"
|
||||
import { render, screen } from "@testing-library/react"
|
||||
|
|
92
nest_frontend/objects/Condition.js
Normal file
92
nest_frontend/objects/Condition.js
Normal file
|
@ -0,0 +1,92 @@
|
|||
import { IconDefinition, faQuestionCircle } from "@fortawesome/free-solid-svg-icons"
|
||||
|
||||
|
||||
/**
|
||||
* Condition class for an undefined/unknown condition.
|
||||
*
|
||||
* See [the Condition spec](https://gitlab.steffo.eu/nest/g2-progetto/-/wikis/sprint-2/Specifica-delle-Conditions).
|
||||
*/
|
||||
export class Condition {
|
||||
content
|
||||
type
|
||||
id
|
||||
|
||||
constructor(type, content, id = null) {
|
||||
this.content = content
|
||||
this.type = type
|
||||
this.id = id
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the condition as an object readable by the backend.
|
||||
*
|
||||
* @returns {{id, type, content}}
|
||||
*/
|
||||
serialize() {
|
||||
return {
|
||||
type: this.type,
|
||||
content: this.content,
|
||||
id: this.id,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display parameters for the badge representing this condition.
|
||||
*
|
||||
* @returns {{color: string, icon: IconDefinition, title, content}}
|
||||
*/
|
||||
display() {
|
||||
return {
|
||||
color: "Grey",
|
||||
icon: faQuestionCircle,
|
||||
title: this.id,
|
||||
content: this.content,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Require a tweet to contain a specific hashtag to be gathered.
|
||||
*/
|
||||
export class ConditionHashtag extends Condition {
|
||||
constructor(hashtag, id = null) {
|
||||
super(0, hashtag, id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Require a tweet to be posted by a certain user to be gathered.
|
||||
*/
|
||||
export class ConditionUser extends Condition {
|
||||
constructor(user, id = null) {
|
||||
super(5, user, id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Require a tweet to be posted before or after a certain time to be gathered.
|
||||
*/
|
||||
export class ConditionTime extends Condition {
|
||||
timeRay
|
||||
|
||||
constructor(timeRay, id = null) {
|
||||
super(2, timeRay.toString(), id)
|
||||
this.timeRay = timeRay
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Require a tweet to have coordinates associated and to be posted within the {@link MapArea}.
|
||||
*/
|
||||
export class ConditionLocation extends Condition {
|
||||
mapArea
|
||||
|
||||
constructor(mapArea, id = null) {
|
||||
super(3, mapArea.toString(), id)
|
||||
this.mapArea = mapArea
|
||||
}
|
||||
}
|
56
nest_frontend/objects/Condition.test.js
Normal file
56
nest_frontend/objects/Condition.test.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
import "@testing-library/jest-dom/extend-expect"
|
||||
import { Condition, ConditionHashtag, ConditionLocation, ConditionTime, ConditionUser } from "./Condition"
|
||||
import TimeRay from "./TimeRay"
|
||||
import MapArea from "./MapArea"
|
||||
|
||||
|
||||
test("Condition can be constructed", () => {
|
||||
expect(new Condition(0, "hi")).toBeTruthy()
|
||||
expect(new Condition(0, "hi", 1)).toBeTruthy()
|
||||
})
|
||||
|
||||
test("ConditionHashtag can be constructed", () => {
|
||||
expect(new ConditionHashtag("PdS2021")).toBeTruthy()
|
||||
expect(new ConditionHashtag("PdS2021", 1)).toBeTruthy()
|
||||
})
|
||||
|
||||
test("ConditionUser can be constructed", () => {
|
||||
expect(new ConditionUser("USteffo")).toBeTruthy()
|
||||
expect(new ConditionUser("USteffo", 1)).toBeTruthy()
|
||||
})
|
||||
|
||||
test("ConditionTime can be constructed", () => {
|
||||
const now = new Date()
|
||||
const timeRay = new TimeRay(true, now)
|
||||
|
||||
expect(new ConditionTime(timeRay)).toBeTruthy()
|
||||
expect(new ConditionTime(timeRay, 1)).toBeTruthy()
|
||||
})
|
||||
|
||||
test("ConditionLocation can be constructed", () => {
|
||||
const mapArea = new MapArea(1000, 0.000, 0.000)
|
||||
|
||||
expect(new ConditionLocation(mapArea)).toBeTruthy()
|
||||
expect(new ConditionLocation(mapArea, 1)).toBeTruthy()
|
||||
})
|
||||
|
||||
test("ConditionHashtag has the correct type", () => {
|
||||
expect(new ConditionHashtag("PdS2021").type).toBe(0)
|
||||
})
|
||||
|
||||
test("ConditionUser has the correct type", () => {
|
||||
expect(new ConditionUser("USteffo").type).toBe(5)
|
||||
})
|
||||
|
||||
test("ConditionTime has the correct type", () => {
|
||||
const now = new Date()
|
||||
const timeRay = new TimeRay(true, now)
|
||||
|
||||
expect(new ConditionTime(timeRay).type).toBe(5)
|
||||
})
|
||||
|
||||
test("ConditionLocation has the correct type", () => {
|
||||
const mapArea = new MapArea(1000, 0.000, 0.000)
|
||||
|
||||
expect(new ConditionLocation(mapArea).type).toBe(3)
|
||||
})
|
104
nest_frontend/objects/Errors.js
Normal file
104
nest_frontend/objects/Errors.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* Error thrown when a function is not implemented in the current class/instance.
|
||||
*/
|
||||
class NotImplementedError {
|
||||
name
|
||||
|
||||
constructor(name) {
|
||||
this.name = name
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An error in the N.E.S.T. frontend-backend communication.
|
||||
*/
|
||||
class BackendCommunicationError {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Error thrown when trying to access a backend view which doesn't exist or isn't allowed in the used hook.
|
||||
*/
|
||||
class ViewNotAllowedError extends BackendCommunicationError {
|
||||
view
|
||||
|
||||
constructor(view) {
|
||||
super()
|
||||
|
||||
this.view = view
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Error thrown when trying to access a backend view when outside a {@link ContextServer}.
|
||||
*/
|
||||
class ServerNotConfiguredError extends BackendCommunicationError {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Error thrown when trying to access a backend view while another access is ongoing.
|
||||
*
|
||||
* This is not allowed due to potential race conditions.
|
||||
*/
|
||||
class FetchAlreadyRunningError extends BackendCommunicationError {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abstract class for {@link DecodeError} and {@link ResultError}.
|
||||
*/
|
||||
class FetchError extends BackendCommunicationError {
|
||||
status
|
||||
statusText
|
||||
|
||||
constructor(status, statusText) {
|
||||
super()
|
||||
|
||||
this.status = status
|
||||
this.statusText = statusText
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Error thrown when the frontend can't parse the data received from the backend.
|
||||
*/
|
||||
class DecodeError extends FetchError {
|
||||
error
|
||||
|
||||
constructor(status, statusText, error) {
|
||||
super(status, statusText)
|
||||
|
||||
this.error = error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Error thrown when the backend returns a falsy `"result"` value.
|
||||
*/
|
||||
class ResultError extends FetchError {
|
||||
status
|
||||
statusText
|
||||
data
|
||||
|
||||
constructor(status, statusText, data) {
|
||||
super(status, statusText)
|
||||
|
||||
this.data = data
|
||||
}
|
||||
|
||||
getMsg() {
|
||||
return this.data.msg
|
||||
}
|
||||
|
||||
getCode() {
|
||||
return this.data.code
|
||||
}
|
||||
}
|
34
nest_frontend/objects/MapArea.js
Normal file
34
nest_frontend/objects/MapArea.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* An area on a map, defined by a latitude `lat`, a longitude `lng` and a radius `rad` in meters.
|
||||
*/
|
||||
export default class MapArea {
|
||||
/**
|
||||
* @param rad - Radius of the area in meters.
|
||||
* @param lat - Latitude of the center of the radius.
|
||||
* @param lng - Longitude of the center of the radius.
|
||||
*/
|
||||
constructor(rad, lat, lng) {
|
||||
this.rad = rad
|
||||
this.lat = lat
|
||||
this.lng = lng
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
toString() {
|
||||
return `${this.rad} ${this.lat.toFixed(7)} ${this.lng.toFixed(7)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the MapArea as an human-readable string.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
toHumanString() {
|
||||
if(this.rad >= 2000) {
|
||||
const kmRadius = Math.round(this.rad / 1000)
|
||||
return `${kmRadius}km ${this.lat.toFixed(3)} ${this.lng.toFixed(3)}`
|
||||
}
|
||||
}
|
||||
}
|
24
nest_frontend/objects/TimeRay.js
Normal file
24
nest_frontend/objects/TimeRay.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* An half-line of time, defined by a `date` and a boolean `isBefore` indicating if the time before or after the
|
||||
* specified date should be selected.
|
||||
*/
|
||||
export default class TimeRay {
|
||||
isBefore
|
||||
date
|
||||
|
||||
/**
|
||||
* @param isBefore - `true` to select times earlier than the date, `false` to select times after the date.
|
||||
* @param date - The date to start measurements from.
|
||||
*/
|
||||
constructor(isBefore, date) {
|
||||
this.isBefore = isBefore
|
||||
this.date = date
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
toString() {
|
||||
return `${this.isBefore ? "<" : ">"} ${this.date.toISOString()}`
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
import isString from "is-string"
|
||||
|
||||
|
||||
const typeEnums = {
|
||||
"HASHTAG": 0,
|
||||
"TIME": 2,
|
||||
"COORDINATES": 3,
|
||||
"PLACE": 4,
|
||||
"USER": 5,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A search/filtering Condition.
|
||||
*
|
||||
* See https://gitlab.steffo.eu/nest/g2-progetto/-/wikis/Specifica-delle-Conditions .
|
||||
*/
|
||||
export default class Condition {
|
||||
|
||||
/**
|
||||
* Create a new Condition.
|
||||
*
|
||||
* @param type - The type of Condition to create.
|
||||
* It can be a number or one of the following strings:
|
||||
* `"hashtag"`, `"time"`, `"coordinates"`, `"place"`.
|
||||
* @param content - The content of the Condition.
|
||||
* @param id - The id of the Condition on the backend, or null if the Condition hasn't been committed yet.
|
||||
*/
|
||||
constructor(type, content, id = null) {
|
||||
if(isString(type)) {
|
||||
this.type = typeEnums[type.toUpperCase()]
|
||||
}
|
||||
else {
|
||||
this.type = type
|
||||
}
|
||||
|
||||
this.content = content
|
||||
this.id = id
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
class NestError {
|
||||
|
||||
}
|
||||
|
||||
|
||||
class ViewNotAllowedError extends NestError {
|
||||
view
|
||||
|
||||
constructor(view) {
|
||||
super()
|
||||
|
||||
this.view = view
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ServerNotConfiguredError extends NestError {
|
||||
|
||||
}
|
||||
|
||||
|
||||
class FetchAlreadyRunningError extends NestError {
|
||||
|
||||
}
|
||||
|
||||
|
||||
class FetchError extends NestError {
|
||||
status
|
||||
statusText
|
||||
|
||||
constructor(status, statusText) {
|
||||
super()
|
||||
|
||||
this.status = status
|
||||
this.statusText = statusText
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DecodeError extends FetchError {
|
||||
error
|
||||
|
||||
constructor(status, statusText, error) {
|
||||
super(status, statusText)
|
||||
|
||||
this.error = error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ResultError extends FetchError {
|
||||
status
|
||||
statusText
|
||||
data
|
||||
|
||||
constructor(status, statusText, data) {
|
||||
super(status, statusText)
|
||||
|
||||
this.data = data
|
||||
}
|
||||
|
||||
getMsg() {
|
||||
return this.data.msg
|
||||
}
|
||||
|
||||
getCode() {
|
||||
return this.data.code
|
||||
}
|
||||
}
|
11
package-lock.json
generated
11
package-lock.json
generated
|
@ -20,6 +20,7 @@
|
|||
"@testing-library/user-event": "^12.8.3",
|
||||
"chart.js": "^3.2.1",
|
||||
"classnames": "^2.3.1",
|
||||
"geolib": "^3.3.1",
|
||||
"is-string": "^1.0.5",
|
||||
"leaflet": "^1.7.1",
|
||||
"react": "^17.0.2",
|
||||
|
@ -9416,6 +9417,11 @@
|
|||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/geolib": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/geolib/-/geolib-3.3.1.tgz",
|
||||
"integrity": "sha512-sfahBXFcgELdpumDZV5b3KWiINkZxC5myAkLk067UUcTmTXaiE9SWmxMEHztn/Eus4JX6kesHxaIuZlniYgUtg=="
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
|
@ -30086,6 +30092,11 @@
|
|||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
|
||||
},
|
||||
"geolib": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/geolib/-/geolib-3.3.1.tgz",
|
||||
"integrity": "sha512-sfahBXFcgELdpumDZV5b3KWiINkZxC5myAkLk067UUcTmTXaiE9SWmxMEHztn/Eus4JX6kesHxaIuZlniYgUtg=="
|
||||
},
|
||||
"get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
"@testing-library/user-event": "^12.8.3",
|
||||
"chart.js": "^3.2.1",
|
||||
"classnames": "^2.3.1",
|
||||
"geolib": "^3.3.1",
|
||||
"is-string": "^1.0.5",
|
||||
"leaflet": "^1.7.1",
|
||||
"react": "^17.0.2",
|
||||
|
|
Loading…
Reference in a new issue