mirror of
https://github.com/pds-nest/nest.git
synced 2024-11-29 07:54:19 +00:00
⤴ Merge, resolving conflicts
This commit is contained in:
commit
7a4e99c4f1
10 changed files with 318 additions and 2 deletions
|
@ -36,6 +36,10 @@ class IntegerParameterSchema(Schema):
|
||||||
rid = fields.Integer(description="The target numeric id.")
|
rid = fields.Integer(description="The target numeric id.")
|
||||||
|
|
||||||
|
|
||||||
|
class AlertParameterSchema(Schema):
|
||||||
|
rid = fields.Integer(description="The target numeric id.")
|
||||||
|
|
||||||
|
|
||||||
class CreateUser(Schema):
|
class CreateUser(Schema):
|
||||||
email = fields.String(description="The new user's email.")
|
email = fields.String(description="The new user's email.")
|
||||||
username = fields.String(description="The new user's username.")
|
username = fields.String(description="The new user's username.")
|
||||||
|
@ -75,5 +79,38 @@ class CreateCondition(Schema):
|
||||||
content = fields.String(description="The condition content. Meaning may change according to type.")
|
content = fields.String(description="The condition content. Meaning may change according to type.")
|
||||||
|
|
||||||
|
|
||||||
|
class CreateAlert(Schema):
|
||||||
|
name = fields.String(description="The name of the alert.")
|
||||||
|
limit = fields.Integer(description="The number of tweets in a time window.")
|
||||||
|
window_size = fields.Integer(description="The size of the time window.")
|
||||||
|
|
||||||
|
|
||||||
|
class Operations(Schema):
|
||||||
|
id = fields.Integer(description="The operation id.")
|
||||||
|
operation = fields.Integer(description="The type of the operation.")
|
||||||
|
is_root = fields.Boolean(description="If true, the operation is the root of the operation tree.")
|
||||||
|
node_1 = fields.Nested('self')
|
||||||
|
node_2 = fields.Nested('self')
|
||||||
|
condition = fields.Nested(ConditionSchema)
|
||||||
|
alert_id = fields.Integer(description="The id of the related alert.")
|
||||||
|
|
||||||
|
|
||||||
|
class Notification(Schema):
|
||||||
|
id = fields.Integer(description="The notification id.")
|
||||||
|
ora = fields.DateTime(description="Muda muda muda.")
|
||||||
|
repository_id = fields.Integer(description="The id of the related repository.")
|
||||||
|
|
||||||
|
|
||||||
|
class Alert(Schema):
|
||||||
|
id = fields.Integer(description="The alert id.")
|
||||||
|
name = fields.String(description="The name of the alert.")
|
||||||
|
limit = fields.Integer(description="The number of tweets in a time window.")
|
||||||
|
window_size = fields.Integer(description="The size of the time window.")
|
||||||
|
repository_id = fields.Integer(description="The id of the related repository.")
|
||||||
|
operations = fields.Nested(Operations, many=True)
|
||||||
|
root_operation = fields.Nested(Operations, many=False)
|
||||||
|
notifications = fields.Nested(Notification, many=True)
|
||||||
|
|
||||||
|
|
||||||
class ConditionParameterSchema(Schema):
|
class ConditionParameterSchema(Schema):
|
||||||
cid = fields.Integer(description="The condition id.")
|
cid = fields.Integer(description="The condition id.")
|
||||||
|
|
|
@ -29,6 +29,9 @@ spec.components.schema("RepositoryUpdate", schema=RepositoryUpdate)
|
||||||
spec.components.schema("CreateRepository", schema=CreateRepository)
|
spec.components.schema("CreateRepository", schema=CreateRepository)
|
||||||
spec.components.schema("CreateCondition", schema=CreateCondition)
|
spec.components.schema("CreateCondition", schema=CreateCondition)
|
||||||
spec.components.schema("ConditionParameter", schema=ConditionParameterSchema)
|
spec.components.schema("ConditionParameter", schema=ConditionParameterSchema)
|
||||||
|
spec.components.schema("AlertParameter", schema=AlertParameterSchema)
|
||||||
|
spec.components.schema("Alert", schema=Alert)
|
||||||
|
spec.components.schema("CreateAlert", schema=CreateAlert)
|
||||||
spec.components.security_scheme("jwt", {"type": "http", "scheme": "bearer", "bearerFormat": "JWT"})
|
spec.components.security_scheme("jwt", {"type": "http", "scheme": "bearer", "bearerFormat": "JWT"})
|
||||||
|
|
||||||
# add swagger tags that are used for endpoint annotation
|
# add swagger tags that are used for endpoint annotation
|
||||||
|
@ -42,6 +45,9 @@ tags = [
|
||||||
{'name': 'condition-related',
|
{'name': 'condition-related',
|
||||||
'description': 'Condition related calls of the API.'
|
'description': 'Condition related calls of the API.'
|
||||||
},
|
},
|
||||||
|
{'name': 'alert-related',
|
||||||
|
'description': 'Alert related calls of the API.'
|
||||||
|
},
|
||||||
{'name': 'admin-only',
|
{'name': 'admin-only',
|
||||||
'description': 'Admin only calls of the API.'
|
'description': 'Admin only calls of the API.'
|
||||||
},
|
},
|
||||||
|
|
|
@ -62,6 +62,11 @@ app.add_url_rule(
|
||||||
view_func=routes.page_repository_conditions,
|
view_func=routes.page_repository_conditions,
|
||||||
methods=["GET", "POST"],
|
methods=["GET", "POST"],
|
||||||
)
|
)
|
||||||
|
app.add_url_rule(
|
||||||
|
"/api/v1/repositories/<int:rid>/alerts",
|
||||||
|
view_func=routes.page_repository_alerts,
|
||||||
|
methods=["GET", "POST"]
|
||||||
|
)
|
||||||
app.add_url_rule(
|
app.add_url_rule(
|
||||||
"/api/v1/conditions/<int:cid>",
|
"/api/v1/conditions/<int:cid>",
|
||||||
view_func=routes.page_condition,
|
view_func=routes.page_condition,
|
||||||
|
|
|
@ -17,3 +17,16 @@ class Alert(ext.Model):
|
||||||
repository = ext.relationship("Repository", back_populates="alerts")
|
repository = ext.relationship("Repository", back_populates="alerts")
|
||||||
notifications = ext.relationship("Notification", back_populates="alert", cascade="all, delete")
|
notifications = ext.relationship("Notification", back_populates="alert", cascade="all, delete")
|
||||||
operations = ext.relationship("BoolOperation", back_populates="alert", cascade="all, delete")
|
operations = ext.relationship("BoolOperation", back_populates="alert", cascade="all, delete")
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
'id': self.id,
|
||||||
|
'name': self.name,
|
||||||
|
'window_size': self.window_size,
|
||||||
|
'limit': self.limit,
|
||||||
|
'repository_id': self.repository_id,
|
||||||
|
'notifications': [notification.to_json() for notification in self.notifications],
|
||||||
|
'operations': [operation.to_json() for operation in self.operations],
|
||||||
|
'root_operation': [operation.to_json() for operation in self.operations if operation.is_root == True][
|
||||||
|
0] if self.operations else None
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ from sqlalchemy.orm import backref
|
||||||
|
|
||||||
class BoolOperation(ext.Model):
|
class BoolOperation(ext.Model):
|
||||||
__tablename__ = "bool_operation"
|
__tablename__ = "bool_operation"
|
||||||
|
|
||||||
id = ext.Column(ext.Integer, primary_key=True)
|
id = ext.Column(ext.Integer, primary_key=True)
|
||||||
operation = ext.Column(ext.Enum(OperationType), nullable=False)
|
operation = ext.Column(ext.Enum(OperationType), nullable=False)
|
||||||
isRoot = ext.Column(ext.Boolean, default=False, nullable=False)
|
isRoot = ext.Column(ext.Boolean, default=False, nullable=False)
|
||||||
|
@ -24,3 +25,13 @@ class BoolOperation(ext.Model):
|
||||||
node_2 = ext.relationship("BoolOperation", primaryjoin=("bool_operation.c.node_2_id==bool_operation.c.id"),
|
node_2 = ext.relationship("BoolOperation", primaryjoin=("bool_operation.c.node_2_id==bool_operation.c.id"),
|
||||||
remote_side="BoolOperation.id", backref=backref("father_2", uselist=False))
|
remote_side="BoolOperation.id", backref=backref("father_2", uselist=False))
|
||||||
alert = ext.relationship("Alert", back_populates="operations")
|
alert = ext.relationship("Alert", back_populates="operations")
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {"id": self.id,
|
||||||
|
"operation": self.operation,
|
||||||
|
"is_root": self.is_root,
|
||||||
|
"alert_id": self.alert_id,
|
||||||
|
"condition": self.condition.to_json() if self.condition else None,
|
||||||
|
"node_1": self.node_1.to_json() if self.node_1 else None,
|
||||||
|
"node_2": self.node_2.to_json() if self.node_2 else None
|
||||||
|
}
|
||||||
|
|
|
@ -13,3 +13,10 @@ class Notification(ext.Model):
|
||||||
alert_id = ext.Column(ext.Integer, ext.ForeignKey("alert.id"), nullable=False)
|
alert_id = ext.Column(ext.Integer, ext.ForeignKey("alert.id"), nullable=False)
|
||||||
# Relationships
|
# Relationships
|
||||||
alert = ext.relationship("Alert", back_populates="notifications")
|
alert = ext.relationship("Alert", back_populates="notifications")
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
"id": self.id,
|
||||||
|
"ora": self.ora.isoformat(),
|
||||||
|
"alert_id": self.alert_id
|
||||||
|
}
|
||||||
|
|
|
@ -2,3 +2,4 @@ from .conditions import page_repository_conditions
|
||||||
from .repository import page_repository
|
from .repository import page_repository
|
||||||
from .repositories import page_repositories
|
from .repositories import page_repositories
|
||||||
from .conditions import *
|
from .conditions import *
|
||||||
|
from .alerts import *
|
|
@ -0,0 +1,2 @@
|
||||||
|
from .repository_alerts import page_repository_alerts
|
||||||
|
from .alert import page_alert
|
142
code/backend/nest_backend/routes/repository/alerts/alert.py
Normal file
142
code/backend/nest_backend/routes/repository/alerts/alert.py
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
from flask import render_template, abort, jsonify, request
|
||||||
|
from nest_backend.database import *
|
||||||
|
from flask_jwt_extended import jwt_required
|
||||||
|
from nest_backend.gestione import *
|
||||||
|
from flask_cors import cross_origin
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
@cross_origin()
|
||||||
|
@jwt_required()
|
||||||
|
@repository_auth
|
||||||
|
def page_alert(aid):
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
get:
|
||||||
|
summary: Get details about an alert.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
schema: AlertParameterSchema
|
||||||
|
security:
|
||||||
|
- jwt: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: The details about the requested alert. The schema is incapsulated in Success.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Alert
|
||||||
|
'404':
|
||||||
|
description: Could not find the requested repository.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
'403':
|
||||||
|
description: The user is not authorized.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
'401':
|
||||||
|
description: The user is not logged in.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
tags:
|
||||||
|
- alert-related
|
||||||
|
delete:
|
||||||
|
summary: Deletes an alert.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
schema: AlertParameterSchema
|
||||||
|
security:
|
||||||
|
- jwt: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: The repository has been deleted successfully.
|
||||||
|
'404':
|
||||||
|
description: Could not find the requested repository.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
'403':
|
||||||
|
description: The user is not authorized.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
'401':
|
||||||
|
description: The user is not logged in.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
'500':
|
||||||
|
description: Could not delete the repository.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
tags:
|
||||||
|
- alert-related
|
||||||
|
patch:
|
||||||
|
summary: Updates an alert.
|
||||||
|
security:
|
||||||
|
- jwt: []
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: CreateAlert
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
schema: AlertParameterSchema
|
||||||
|
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: The repository has been updated successfully.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Alert
|
||||||
|
'404':
|
||||||
|
description: Could not find the requested repository.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
'403':
|
||||||
|
description: The user is not authorized.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
'401':
|
||||||
|
description: The user is not logged in.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
tags:
|
||||||
|
- alert-related
|
||||||
|
"""
|
||||||
|
user = find_user(get_jwt_identity())
|
||||||
|
alert = Alert.query.filter_by(id=aid).first()
|
||||||
|
if not alert:
|
||||||
|
return json_error("Could not find alert."), 404
|
||||||
|
if alert.repository not in [a.repository for a in user.authorizations] + user.owner_of:
|
||||||
|
json_error("You are not authorized to proceed."), 403
|
||||||
|
if request.method == "GET":
|
||||||
|
return json_success(alert.to_json()), 200
|
||||||
|
if alert.repository not in user.owner_of:
|
||||||
|
json_error("You are not authorized to proceed."), 403
|
||||||
|
if request.method == "PATCH":
|
||||||
|
if 'name' in request.json:
|
||||||
|
alert.name = request.json['name']
|
||||||
|
if 'limit' in request.json:
|
||||||
|
alert.limit = request.json['limit']
|
||||||
|
if 'window_size' in request.json:
|
||||||
|
alert.window_size = request.json['window_size']
|
||||||
|
ext.session.commit()
|
||||||
|
return json_success(alert.to_json()), 200
|
||||||
|
elif request.method == "DELETE":
|
||||||
|
try:
|
||||||
|
ext.session.delete(alert)
|
||||||
|
ext.session.commit()
|
||||||
|
except Exception:
|
||||||
|
return json_error("Something went wrong while deleting alert."), 500
|
||||||
|
return json_success("Deletion completed."), 200
|
||||||
|
elif request.method == "PUT":
|
||||||
|
pass
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
from flask import render_template, abort, jsonify, request
|
||||||
|
from nest_backend.database import *
|
||||||
|
from flask_jwt_extended import jwt_required
|
||||||
|
from nest_backend.gestione import *
|
||||||
|
from flask_cors import cross_origin
|
||||||
|
|
||||||
|
|
||||||
|
@cross_origin()
|
||||||
|
@jwt_required()
|
||||||
|
@repository_auth
|
||||||
|
def page_repository_alerts(rid):
|
||||||
|
"""
|
||||||
|
---
|
||||||
|
get:
|
||||||
|
summary: Get a list of a repository alerts.
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
schema: IntegerParameterSchema
|
||||||
|
security:
|
||||||
|
- jwt: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: List of Alert schemas, incapsulated in Success.
|
||||||
|
'401':
|
||||||
|
description: The user is not logged in.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
'403':
|
||||||
|
description: The user is not authorized.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
'404':
|
||||||
|
description: The repository could not be found.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
tags:
|
||||||
|
- repository-related
|
||||||
|
post:
|
||||||
|
summary: Creates an alert and attaches it to the repository.
|
||||||
|
security:
|
||||||
|
- jwt: []
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: CreateAlert
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: The alert has been created successfully.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Alert
|
||||||
|
'403':
|
||||||
|
description: The user is not authorized.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
'401':
|
||||||
|
description: The user is not logged in.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema: Error
|
||||||
|
tags:
|
||||||
|
- alert-related
|
||||||
|
"""
|
||||||
|
|
||||||
|
repository = Repository.query.filter_by(id=rid).first()
|
||||||
|
if not repository:
|
||||||
|
return json_error("Could not find repository"), 404
|
||||||
|
user = find_user(get_jwt_identity())
|
||||||
|
if user.email != repository.owner_id:
|
||||||
|
return json_error("You are not authorized."), 403
|
||||||
|
|
||||||
|
if request.method == "GET":
|
||||||
|
return json_success([alert.to_json() for alert in repository.alerts])
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
if 'name' not in request.json:
|
||||||
|
json_error("Missing name."), 400
|
||||||
|
if 'limit' not in request.json:
|
||||||
|
json_error('Missing limit'), 400
|
||||||
|
if 'window_size' not in request.json:
|
||||||
|
json_error('Missing window size'), 400
|
||||||
|
alert = Alert(name=request.json['name'], limit=request.json['limit'], window_size=request.json['window_size'],
|
||||||
|
repository_id=rid)
|
||||||
|
ext.session.add(alert)
|
||||||
|
ext.session.commit()
|
||||||
|
|
||||||
|
return json_success(alert.to_json()), 200
|
Loading…
Reference in a new issue