This commit is contained in:
0
iris-web/source/app/datamgmt/case/__init__.py
Normal file
0
iris-web/source/app/datamgmt/case/__init__.py
Normal file
399
iris-web/source/app/datamgmt/case/case_assets_db.py
Normal file
399
iris-web/source/app/datamgmt/case/case_assets_db.py
Normal file
@ -0,0 +1,399 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# IRIS Source Code
|
||||
# Copyright (C) 2021 - Airbus CyberSecurity (SAS)
|
||||
# ir@cyberactionlab.net
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import datetime
|
||||
|
||||
from flask_login import current_user
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import func
|
||||
|
||||
from app import db, app
|
||||
from app.datamgmt.states import update_assets_state
|
||||
from app.models import AnalysisStatus, CaseStatus
|
||||
from app.models import AssetComments
|
||||
from app.models import AssetsType
|
||||
from app.models import CaseAssets
|
||||
from app.models import CaseEventsAssets
|
||||
from app.models import Cases
|
||||
from app.models import Comments
|
||||
from app.models import CompromiseStatus
|
||||
from app.models import Ioc
|
||||
from app.models import IocAssetLink
|
||||
from app.models import IocLink
|
||||
from app.models import IocType
|
||||
from app.models.authorization import User
|
||||
|
||||
|
||||
log = app.logger
|
||||
|
||||
def create_asset(asset, caseid, user_id):
|
||||
|
||||
asset.date_added = datetime.datetime.utcnow()
|
||||
asset.date_update = datetime.datetime.utcnow()
|
||||
asset.case_id = caseid
|
||||
asset.user_id = user_id
|
||||
|
||||
db.session.add(asset)
|
||||
update_assets_state(caseid=caseid, userid=user_id)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return asset
|
||||
|
||||
|
||||
def get_assets(caseid):
|
||||
assets = CaseAssets.query.with_entities(
|
||||
CaseAssets.asset_id,
|
||||
CaseAssets.asset_uuid,
|
||||
CaseAssets.asset_name,
|
||||
AssetsType.asset_name.label('asset_type'),
|
||||
AssetsType.asset_icon_compromised,
|
||||
AssetsType.asset_icon_not_compromised,
|
||||
CaseAssets.asset_description,
|
||||
CaseAssets.asset_domain,
|
||||
CaseAssets.asset_compromise_status_id,
|
||||
CaseAssets.asset_ip,
|
||||
CaseAssets.asset_type_id,
|
||||
AnalysisStatus.name.label('analysis_status'),
|
||||
CaseAssets.analysis_status_id,
|
||||
CaseAssets.asset_tags
|
||||
).filter(
|
||||
CaseAssets.case_id == caseid,
|
||||
).join(
|
||||
CaseAssets.asset_type, CaseAssets.analysis_status
|
||||
).all()
|
||||
|
||||
return assets
|
||||
|
||||
|
||||
def get_assets_name(caseid):
|
||||
assets_names = CaseAssets.query.with_entities(
|
||||
CaseAssets.asset_name
|
||||
).filter(
|
||||
CaseAssets.case_id == caseid
|
||||
).all()
|
||||
|
||||
return assets_names
|
||||
|
||||
|
||||
def get_asset(asset_id, caseid):
|
||||
asset = CaseAssets.query.filter(
|
||||
CaseAssets.asset_id == asset_id,
|
||||
CaseAssets.case_id == caseid
|
||||
).first()
|
||||
|
||||
return asset
|
||||
|
||||
|
||||
def update_asset(asset_name, asset_description, asset_ip, asset_info, asset_domain,
|
||||
asset_compromise_status_id, asset_type, asset_id, caseid, analysis_status, asset_tags):
|
||||
asset = get_asset(asset_id, caseid)
|
||||
asset.asset_name = asset_name
|
||||
asset.asset_description = asset_description
|
||||
asset.asset_ip = asset_ip
|
||||
asset.asset_info = asset_info
|
||||
asset.asset_domain = asset_domain
|
||||
asset.asset_compromise_status_id = asset_compromise_status_id
|
||||
asset.asset_type_id = asset_type
|
||||
asset.analysis_status_id = analysis_status
|
||||
asset.asset_tags = asset_tags
|
||||
|
||||
update_assets_state(caseid=caseid)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def delete_asset(asset_id, caseid):
|
||||
case_asset = get_asset(asset_id, caseid)
|
||||
if case_asset is None:
|
||||
return
|
||||
|
||||
if case_asset.case_id and case_asset.alerts is not None:
|
||||
|
||||
CaseEventsAssets.query.filter(
|
||||
case_asset.asset_id == CaseEventsAssets.asset_id
|
||||
).delete()
|
||||
|
||||
case_asset.case_id = None
|
||||
db.session.commit()
|
||||
return
|
||||
|
||||
with db.session.begin_nested():
|
||||
delete_ioc_asset_link(asset_id)
|
||||
|
||||
# Delete the relevant records from the CaseEventsAssets table
|
||||
CaseEventsAssets.query.filter(
|
||||
CaseEventsAssets.case_id == caseid,
|
||||
CaseEventsAssets.asset_id == asset_id
|
||||
).delete()
|
||||
|
||||
# Delete the relevant records from the AssetComments table
|
||||
com_ids = AssetComments.query.with_entities(
|
||||
AssetComments.comment_id
|
||||
).filter(
|
||||
AssetComments.comment_asset_id == asset_id,
|
||||
).all()
|
||||
|
||||
com_ids = [c.comment_id for c in com_ids]
|
||||
AssetComments.query.filter(AssetComments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
Comments.query.filter(
|
||||
Comments.comment_id.in_(com_ids)
|
||||
).delete()
|
||||
|
||||
# Directly delete the relevant records from the CaseAssets table
|
||||
CaseAssets.query.filter(
|
||||
CaseAssets.asset_id == asset_id,
|
||||
CaseAssets.case_id == caseid
|
||||
).delete()
|
||||
|
||||
update_assets_state(caseid=caseid)
|
||||
|
||||
|
||||
def get_assets_types():
|
||||
assets_types = [(c.asset_id, c.asset_name) for c
|
||||
in AssetsType.query.with_entities(AssetsType.asset_name,
|
||||
AssetsType.asset_id).order_by(AssetsType.asset_name)
|
||||
]
|
||||
|
||||
return assets_types
|
||||
|
||||
|
||||
def get_unspecified_analysis_status_id():
|
||||
"""
|
||||
Get the id of the 'Unspecified' analysis status
|
||||
"""
|
||||
analysis_status = AnalysisStatus.query.filter(
|
||||
AnalysisStatus.name == 'Unspecified'
|
||||
).first()
|
||||
|
||||
return analysis_status.id if analysis_status else None
|
||||
|
||||
|
||||
def get_analysis_status_list():
|
||||
analysis_status = [(c.id, c.name) for c in AnalysisStatus.query.with_entities(
|
||||
AnalysisStatus.id,
|
||||
AnalysisStatus.name
|
||||
)]
|
||||
|
||||
return analysis_status
|
||||
|
||||
|
||||
def get_compromise_status_list():
|
||||
return [(e.value, e.name.replace('_', ' ').capitalize()) for e in CompromiseStatus]
|
||||
|
||||
|
||||
def get_compromise_status_dict():
|
||||
return [{'value': e.value, 'name': e.name.replace('_', ' ').capitalize()} for e in CompromiseStatus]
|
||||
|
||||
|
||||
def get_case_outcome_status_dict():
|
||||
return [{'value': e.value, 'name': e.name.replace('_', ' ').capitalize()} for e in CaseStatus]
|
||||
|
||||
|
||||
def get_asset_type_id(asset_type_name):
|
||||
assets_type_id = AssetsType.query.with_entities(
|
||||
AssetsType.asset_id
|
||||
).filter(
|
||||
func.lower(AssetsType.asset_name) == asset_type_name
|
||||
).first()
|
||||
|
||||
return assets_type_id
|
||||
|
||||
|
||||
def get_assets_ioc_links(caseid):
|
||||
|
||||
ioc_links_req = IocAssetLink.query.with_entities(
|
||||
Ioc.ioc_id,
|
||||
Ioc.ioc_value,
|
||||
IocAssetLink.asset_id
|
||||
).filter(
|
||||
Ioc.ioc_id == IocAssetLink.ioc_id,
|
||||
IocLink.case_id == caseid,
|
||||
IocLink.ioc_id == Ioc.ioc_id
|
||||
).all()
|
||||
|
||||
return ioc_links_req
|
||||
|
||||
def get_similar_assets(asset_name, asset_type_id, caseid, customer_id, cases_limitation):
|
||||
|
||||
linked_assets = CaseAssets.query.with_entities(
|
||||
Cases.name.label('case_name'),
|
||||
Cases.open_date.label('case_open_date'),
|
||||
CaseAssets.asset_description,
|
||||
CaseAssets.asset_compromise_status_id,
|
||||
CaseAssets.asset_id,
|
||||
CaseAssets.case_id
|
||||
).filter(
|
||||
Cases.client_id == customer_id,
|
||||
CaseAssets.case_id != caseid
|
||||
).filter(
|
||||
CaseAssets.asset_name == asset_name,
|
||||
CaseAssets.asset_type_id == asset_type_id,
|
||||
Cases.case_id.in_(cases_limitation)
|
||||
).join(CaseAssets.case).all()
|
||||
|
||||
return (lasset._asdict() for lasset in linked_assets)
|
||||
|
||||
|
||||
def delete_ioc_asset_link(asset_id):
|
||||
IocAssetLink.query.filter(
|
||||
IocAssetLink.asset_id == asset_id
|
||||
).delete()
|
||||
|
||||
|
||||
def get_linked_iocs_from_asset(asset_id):
|
||||
iocs = IocAssetLink.query.with_entities(
|
||||
Ioc.ioc_id,
|
||||
Ioc.ioc_value
|
||||
).filter(
|
||||
IocAssetLink.asset_id == asset_id,
|
||||
Ioc.ioc_id == IocAssetLink.ioc_id
|
||||
).all()
|
||||
|
||||
return iocs
|
||||
|
||||
|
||||
def set_ioc_links(ioc_list, asset_id):
|
||||
if ioc_list is None:
|
||||
return False, "Empty IOC list"
|
||||
|
||||
# Reset IOC list
|
||||
delete_ioc_asset_link(asset_id)
|
||||
|
||||
for ioc in ioc_list:
|
||||
ial = IocAssetLink()
|
||||
ial.asset_id = asset_id
|
||||
ial.ioc_id = ioc
|
||||
|
||||
db.session.add(ial)
|
||||
|
||||
try:
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
log.exception(e)
|
||||
return True, e.__str__()
|
||||
|
||||
return False, ""
|
||||
|
||||
|
||||
def get_linked_iocs_id_from_asset(asset_id):
|
||||
iocs = IocAssetLink.query.with_entities(
|
||||
IocAssetLink.ioc_id
|
||||
).filter(
|
||||
IocAssetLink.asset_id == asset_id
|
||||
).all()
|
||||
|
||||
return iocs
|
||||
|
||||
|
||||
def get_linked_iocs_finfo_from_asset(asset_id):
|
||||
iocs = IocAssetLink.query.with_entities(
|
||||
Ioc.ioc_id,
|
||||
Ioc.ioc_value,
|
||||
Ioc.ioc_tags,
|
||||
Ioc.ioc_type_id,
|
||||
IocType.type_name,
|
||||
Ioc.ioc_description,
|
||||
Ioc.ioc_tlp_id
|
||||
).filter(and_(
|
||||
IocAssetLink.asset_id == asset_id,
|
||||
IocAssetLink.ioc_id == Ioc.ioc_id
|
||||
)).join(Ioc.ioc_type).all()
|
||||
|
||||
return iocs
|
||||
|
||||
|
||||
def get_case_asset_comments(asset_id):
|
||||
return Comments.query.filter(
|
||||
AssetComments.comment_asset_id == asset_id
|
||||
).with_entities(
|
||||
Comments
|
||||
).join(AssetComments,
|
||||
Comments.comment_id == AssetComments.comment_id
|
||||
).order_by(
|
||||
Comments.comment_date.asc()
|
||||
).all()
|
||||
|
||||
|
||||
def add_comment_to_asset(asset_id, comment_id):
|
||||
ec = AssetComments()
|
||||
ec.comment_asset_id = asset_id
|
||||
ec.comment_id = comment_id
|
||||
|
||||
db.session.add(ec)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_case_assets_comments_count(asset_id):
|
||||
return AssetComments.query.filter(
|
||||
AssetComments.comment_asset_id.in_(asset_id)
|
||||
).with_entities(
|
||||
AssetComments.comment_asset_id,
|
||||
AssetComments.comment_id
|
||||
).group_by(
|
||||
AssetComments.comment_asset_id,
|
||||
AssetComments.comment_id
|
||||
).all()
|
||||
|
||||
|
||||
def get_case_asset_comment(asset_id, comment_id):
|
||||
return AssetComments.query.filter(
|
||||
AssetComments.comment_asset_id == asset_id,
|
||||
AssetComments.comment_id == comment_id
|
||||
).with_entities(
|
||||
Comments.comment_id,
|
||||
Comments.comment_text,
|
||||
Comments.comment_date,
|
||||
Comments.comment_update_date,
|
||||
Comments.comment_uuid,
|
||||
User.name,
|
||||
User.user
|
||||
).join(
|
||||
AssetComments.comment,
|
||||
Comments.user
|
||||
).first()
|
||||
|
||||
|
||||
def delete_asset_comment(asset_id, comment_id, case_id):
|
||||
comment = Comments.query.filter(
|
||||
Comments.comment_id == comment_id,
|
||||
Comments.comment_user_id == current_user.id
|
||||
).first()
|
||||
if not comment:
|
||||
return False, "You are not allowed to delete this comment"
|
||||
|
||||
AssetComments.query.filter(
|
||||
AssetComments.comment_asset_id == asset_id,
|
||||
AssetComments.comment_id == comment_id
|
||||
).delete()
|
||||
|
||||
db.session.delete(comment)
|
||||
db.session.commit()
|
||||
|
||||
return True, "Comment deleted"
|
||||
|
||||
def get_asset_by_name(asset_name, caseid):
|
||||
asset = CaseAssets.query.filter(
|
||||
CaseAssets.asset_name == asset_name,
|
||||
CaseAssets.case_id == caseid
|
||||
).first()
|
||||
return asset
|
13
iris-web/source/app/datamgmt/case/case_comments.py
Normal file
13
iris-web/source/app/datamgmt/case/case_comments.py
Normal file
@ -0,0 +1,13 @@
|
||||
from app.models import Comments
|
||||
|
||||
|
||||
def get_case_comment(comment_id, caseid):
|
||||
if caseid is None:
|
||||
return Comments.query.filter(
|
||||
Comments.comment_id == comment_id
|
||||
).first()
|
||||
else:
|
||||
return Comments.query.filter(
|
||||
Comments.comment_id == comment_id,
|
||||
Comments.comment_case_id == caseid
|
||||
).first()
|
211
iris-web/source/app/datamgmt/case/case_db.py
Normal file
211
iris-web/source/app/datamgmt/case/case_db.py
Normal file
@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# IRIS Source Code
|
||||
# Copyright (C) 2021 - Airbus CyberSecurity (SAS)
|
||||
# ir@cyberactionlab.net
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
import datetime
|
||||
|
||||
import binascii
|
||||
from sqlalchemy import and_
|
||||
|
||||
from app import db
|
||||
from app.models import Tags
|
||||
from app.models.cases import CaseProtagonist
|
||||
from app.models.cases import CaseTags
|
||||
from app.models.cases import Cases
|
||||
from app.models.models import CaseTemplateReport, ReviewStatus
|
||||
from app.models.models import Client
|
||||
from app.models.models import Languages
|
||||
from app.models.models import ReportType
|
||||
from app.models.authorization import User
|
||||
|
||||
|
||||
def get_case_summary(caseid):
|
||||
case_summary = Cases.query.filter(
|
||||
Cases.case_id == caseid
|
||||
).with_entities(
|
||||
Cases.name.label('case_name'),
|
||||
Cases.open_date.label('case_open'),
|
||||
User.name.label('user'),
|
||||
Client.name.label('customer')
|
||||
).join(
|
||||
Cases.user, Cases.client
|
||||
).first()
|
||||
|
||||
return case_summary
|
||||
|
||||
|
||||
def get_case(caseid):
|
||||
return Cases.query.filter(Cases.case_id == caseid).first()
|
||||
|
||||
|
||||
def case_exists(caseid):
|
||||
return Cases.query.filter(Cases.case_id == caseid).count()
|
||||
|
||||
|
||||
def get_case_client_id(caseid):
|
||||
client_id = Cases.query.with_entities(
|
||||
Client.client_id
|
||||
).filter(
|
||||
Cases.case_id == caseid
|
||||
).join(Cases.client).first()
|
||||
|
||||
return client_id.client_id
|
||||
|
||||
|
||||
def case_get_desc(caseid):
|
||||
case_desc = Cases.query.with_entities(
|
||||
Cases.description
|
||||
).filter(
|
||||
Cases.case_id == caseid
|
||||
).first()
|
||||
|
||||
return case_desc
|
||||
|
||||
|
||||
def case_get_desc_crc(caseid):
|
||||
partial_case = case_get_desc(caseid)
|
||||
|
||||
if partial_case:
|
||||
desc = partial_case.description
|
||||
if not desc:
|
||||
desc = ""
|
||||
desc_crc32 = binascii.crc32(desc.encode('utf-8'))
|
||||
else:
|
||||
desc = None
|
||||
desc_crc32 = None
|
||||
|
||||
return desc_crc32, desc
|
||||
|
||||
|
||||
def case_set_desc_crc(desc, caseid):
|
||||
lcase = get_case(caseid)
|
||||
|
||||
if lcase:
|
||||
if not desc:
|
||||
desc = ""
|
||||
lcase.description = desc
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_case_report_template():
|
||||
reports = CaseTemplateReport.query.with_entities(
|
||||
CaseTemplateReport.id,
|
||||
CaseTemplateReport.name,
|
||||
Languages.name,
|
||||
CaseTemplateReport.description
|
||||
).join(
|
||||
CaseTemplateReport.language,
|
||||
CaseTemplateReport.report_type
|
||||
).filter(
|
||||
ReportType.name == "Investigation"
|
||||
).all()
|
||||
|
||||
return reports
|
||||
|
||||
|
||||
def save_case_tags(tags, case):
|
||||
if tags is None:
|
||||
return
|
||||
|
||||
case.tags.clear()
|
||||
|
||||
for tag in tags.split(','):
|
||||
tag = tag.strip()
|
||||
if tag:
|
||||
tg = Tags.query.filter_by(tag_title=tag).first()
|
||||
|
||||
if tg is None:
|
||||
tg = Tags(tag_title=tag)
|
||||
tg.save()
|
||||
|
||||
case.tags.append(tg)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_case_tags(case_id):
|
||||
case = Cases.query.get(case_id)
|
||||
|
||||
if case:
|
||||
return [tag.tag_title for tag in case.tags]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def get_activities_report_template():
|
||||
reports = CaseTemplateReport.query.with_entities(
|
||||
CaseTemplateReport.id,
|
||||
CaseTemplateReport.name,
|
||||
Languages.name,
|
||||
CaseTemplateReport.description
|
||||
).join(
|
||||
CaseTemplateReport.language,
|
||||
CaseTemplateReport.report_type
|
||||
).filter(
|
||||
ReportType.name == "Activities"
|
||||
).all()
|
||||
|
||||
return reports
|
||||
|
||||
|
||||
def case_name_exists(case_name, client_name):
|
||||
res = Cases.query.with_entities(
|
||||
Cases.name, Client.name
|
||||
).filter(and_(
|
||||
Cases.name == case_name,
|
||||
Client.name == client_name
|
||||
)).join(
|
||||
Cases.client
|
||||
).first()
|
||||
|
||||
return True if res else False
|
||||
|
||||
|
||||
def register_case_protagonists(case_id, protagonists):
|
||||
|
||||
if protagonists is None:
|
||||
return
|
||||
|
||||
CaseProtagonist.query.filter(
|
||||
CaseProtagonist.case_id == case_id
|
||||
).delete()
|
||||
|
||||
for protagonist in protagonists:
|
||||
for key in ['role', 'name']:
|
||||
if not protagonist.get(key):
|
||||
continue
|
||||
|
||||
cp = CaseProtagonist()
|
||||
cp.case_id = case_id
|
||||
cp.role = protagonist.get('role')
|
||||
cp.name = protagonist.get('name')
|
||||
cp.contact = protagonist.get('contact')
|
||||
db.session.add(cp)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_review_id_from_name(review_name):
|
||||
status = ReviewStatus.query.filter(ReviewStatus.status_name == review_name).first()
|
||||
if status:
|
||||
return status.id
|
||||
|
||||
return None
|
402
iris-web/source/app/datamgmt/case/case_events_db.py
Normal file
402
iris-web/source/app/datamgmt/case/case_events_db.py
Normal file
@ -0,0 +1,402 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# IRIS Source Code
|
||||
# Copyright (C) 2021 - Airbus CyberSecurity (SAS)
|
||||
# ir@cyberactionlab.net
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
from flask_login import current_user
|
||||
from sqlalchemy import and_
|
||||
|
||||
from app import db
|
||||
from app.datamgmt.states import update_timeline_state
|
||||
from app.models import AssetsType
|
||||
from app.models import CaseAssets
|
||||
from app.models import CaseEventCategory
|
||||
from app.models import CaseEventsAssets
|
||||
from app.models import CaseEventsIoc
|
||||
from app.models import CasesEvent
|
||||
from app.models import Comments
|
||||
from app.models import EventCategory
|
||||
from app.models import EventComments
|
||||
from app.models import Ioc
|
||||
from app.models import IocAssetLink
|
||||
from app.models import IocLink
|
||||
from app.models import IocType
|
||||
from app.models.authorization import User
|
||||
|
||||
|
||||
def get_case_events_assets_graph(caseid):
|
||||
events = CaseEventsAssets.query.with_entities(
|
||||
CaseEventsAssets.event_id,
|
||||
CasesEvent.event_uuid,
|
||||
CasesEvent.event_title,
|
||||
CaseAssets.asset_name,
|
||||
CaseAssets.asset_id,
|
||||
AssetsType.asset_name.label('type_name'),
|
||||
AssetsType.asset_icon_not_compromised,
|
||||
AssetsType.asset_icon_compromised,
|
||||
CasesEvent.event_color,
|
||||
CaseAssets.asset_compromise_status_id,
|
||||
CaseAssets.asset_description,
|
||||
CaseAssets.asset_ip,
|
||||
CasesEvent.event_date,
|
||||
CasesEvent.event_tags
|
||||
).filter(and_(
|
||||
CaseEventsAssets.case_id == caseid,
|
||||
CasesEvent.event_in_graph == True
|
||||
)).join(
|
||||
CaseEventsAssets.event,
|
||||
CaseEventsAssets.asset,
|
||||
CaseAssets.asset_type,
|
||||
).all()
|
||||
|
||||
return events
|
||||
|
||||
|
||||
def get_case_events_ioc_graph(caseid):
|
||||
events = CaseEventsIoc.query.with_entities(
|
||||
CaseEventsIoc.event_id,
|
||||
CasesEvent.event_uuid,
|
||||
CasesEvent.event_title,
|
||||
CasesEvent.event_date,
|
||||
Ioc.ioc_id,
|
||||
Ioc.ioc_value,
|
||||
Ioc.ioc_description,
|
||||
IocType.type_name
|
||||
).filter(and_(
|
||||
CaseEventsIoc.case_id == caseid,
|
||||
CasesEvent.event_in_graph == True
|
||||
)).join(
|
||||
CaseEventsIoc.event,
|
||||
CaseEventsIoc.ioc,
|
||||
Ioc.ioc_type,
|
||||
).all()
|
||||
|
||||
return events
|
||||
|
||||
|
||||
def get_events_categories():
|
||||
return EventCategory.query.with_entities(
|
||||
EventCategory.id,
|
||||
EventCategory.name
|
||||
).all()
|
||||
|
||||
|
||||
def get_default_cat():
|
||||
cat = EventCategory.query.with_entities(
|
||||
EventCategory.id,
|
||||
EventCategory.name
|
||||
).filter(
|
||||
EventCategory.name == "Unspecified"
|
||||
).first()
|
||||
|
||||
return [cat._asdict()]
|
||||
|
||||
|
||||
def get_case_event(event_id, caseid):
|
||||
return CasesEvent.query.filter(
|
||||
CasesEvent.event_id == event_id,
|
||||
CasesEvent.case_id == caseid
|
||||
).first()
|
||||
|
||||
|
||||
def get_case_event_comments(event_id, caseid):
|
||||
return Comments.query.filter(
|
||||
EventComments.comment_event_id == event_id
|
||||
).join(
|
||||
EventComments,
|
||||
Comments.comment_id == EventComments.comment_id
|
||||
).order_by(
|
||||
Comments.comment_date.asc()
|
||||
).all()
|
||||
|
||||
|
||||
def get_case_events_comments_count(events_list):
|
||||
return EventComments.query.filter(
|
||||
EventComments.comment_event_id.in_(events_list)
|
||||
).with_entities(
|
||||
EventComments.comment_event_id,
|
||||
EventComments.comment_id
|
||||
).group_by(
|
||||
EventComments.comment_event_id,
|
||||
EventComments.comment_id
|
||||
).all()
|
||||
|
||||
|
||||
def get_case_event_comment(event_id, comment_id, caseid):
|
||||
return EventComments.query.filter(
|
||||
EventComments.comment_event_id == event_id,
|
||||
EventComments.comment_id == comment_id
|
||||
).with_entities(
|
||||
Comments.comment_id,
|
||||
Comments.comment_text,
|
||||
Comments.comment_date,
|
||||
Comments.comment_update_date,
|
||||
Comments.comment_uuid,
|
||||
User.name,
|
||||
User.user
|
||||
).join(
|
||||
EventComments.comment,
|
||||
Comments.user
|
||||
).first()
|
||||
|
||||
|
||||
def delete_event_comment(event_id, comment_id):
|
||||
comment = Comments.query.filter(
|
||||
Comments.comment_id == comment_id,
|
||||
Comments.comment_user_id == current_user.id
|
||||
).first()
|
||||
if not comment:
|
||||
return False, "You are not allowed to delete this comment"
|
||||
|
||||
EventComments.query.filter(
|
||||
EventComments.comment_event_id == event_id,
|
||||
EventComments.comment_id == comment_id
|
||||
).delete()
|
||||
|
||||
db.session.delete(comment)
|
||||
db.session.commit()
|
||||
|
||||
return True, "Comment deleted"
|
||||
|
||||
|
||||
def add_comment_to_event(event_id, comment_id):
|
||||
ec = EventComments()
|
||||
ec.comment_event_id = event_id
|
||||
ec.comment_id = comment_id
|
||||
|
||||
db.session.add(ec)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def delete_event_category(event_id):
|
||||
CaseEventCategory.query.filter(
|
||||
CaseEventCategory.event_id == event_id
|
||||
).delete()
|
||||
|
||||
|
||||
def get_event_category(event_id):
|
||||
cec = CaseEventCategory.query.filter(
|
||||
CaseEventCategory.event_id == event_id
|
||||
).first()
|
||||
return cec
|
||||
|
||||
|
||||
def save_event_category(event_id, category_id):
|
||||
CaseEventCategory.query.filter(
|
||||
CaseEventCategory.event_id == event_id
|
||||
).delete()
|
||||
|
||||
cec = CaseEventCategory()
|
||||
cec.event_id = event_id
|
||||
cec.category_id = category_id
|
||||
|
||||
db.session.add(cec)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_event_assets_ids(event_id, caseid):
|
||||
assets_list = CaseEventsAssets.query.with_entities(
|
||||
CaseEventsAssets.asset_id
|
||||
).filter(
|
||||
CaseEventsAssets.event_id == event_id,
|
||||
CaseEventsAssets.case_id == caseid
|
||||
).all()
|
||||
|
||||
return [x[0] for x in assets_list]
|
||||
|
||||
|
||||
def get_event_iocs_ids(event_id, caseid):
|
||||
iocs_list = CaseEventsIoc.query.with_entities(
|
||||
CaseEventsIoc.ioc_id
|
||||
).filter(
|
||||
CaseEventsIoc.event_id == event_id,
|
||||
CaseEventsIoc.case_id == caseid
|
||||
).all()
|
||||
|
||||
return [x[0] for x in iocs_list]
|
||||
|
||||
|
||||
def update_event_assets(event_id, caseid, assets_list, iocs_list, sync_iocs_assets):
|
||||
|
||||
CaseEventsAssets.query.filter(
|
||||
CaseEventsAssets.event_id == event_id,
|
||||
CaseEventsAssets.case_id == caseid
|
||||
).delete()
|
||||
|
||||
valid_assets = CaseAssets.query.with_entities(
|
||||
CaseAssets.asset_id
|
||||
).filter(
|
||||
CaseAssets.asset_id.in_(assets_list),
|
||||
CaseAssets.case_id == caseid
|
||||
).all()
|
||||
|
||||
for asset in valid_assets:
|
||||
try:
|
||||
|
||||
cea = CaseEventsAssets()
|
||||
cea.asset_id = int(asset.asset_id)
|
||||
cea.event_id = event_id
|
||||
cea.case_id = caseid
|
||||
|
||||
db.session.add(cea)
|
||||
|
||||
if sync_iocs_assets:
|
||||
for ioc in iocs_list:
|
||||
link = IocAssetLink.query.filter(
|
||||
IocAssetLink.asset_id == int(asset.asset_id),
|
||||
IocAssetLink.ioc_id == int(ioc)
|
||||
).first()
|
||||
|
||||
if link is None:
|
||||
|
||||
ial = IocAssetLink()
|
||||
ial.asset_id = int(asset.asset_id)
|
||||
ial.ioc_id = int(ioc)
|
||||
|
||||
db.session.add(ial)
|
||||
|
||||
except Exception as e:
|
||||
return False, str(e)
|
||||
|
||||
db.session.commit()
|
||||
return True, ''
|
||||
|
||||
|
||||
def update_event_iocs(event_id, caseid, iocs_list):
|
||||
|
||||
CaseEventsIoc.query.filter(
|
||||
CaseEventsIoc.event_id == event_id,
|
||||
CaseEventsIoc.case_id == caseid
|
||||
).delete()
|
||||
|
||||
valid_iocs = IocLink.query.with_entities(
|
||||
IocLink.ioc_id
|
||||
).filter(
|
||||
IocLink.ioc_id.in_(iocs_list),
|
||||
IocLink.case_id == caseid
|
||||
).all()
|
||||
|
||||
for ioc in valid_iocs:
|
||||
try:
|
||||
|
||||
cea = CaseEventsIoc()
|
||||
cea.ioc_id = int(ioc.ioc_id)
|
||||
cea.event_id = event_id
|
||||
cea.case_id = caseid
|
||||
|
||||
db.session.add(cea)
|
||||
|
||||
except Exception as e:
|
||||
return False, str(e)
|
||||
|
||||
db.session.commit()
|
||||
return True, ''
|
||||
|
||||
|
||||
def get_case_assets_for_tm(caseid):
|
||||
"""
|
||||
Return a list of all assets linked to the current case
|
||||
:return: Tuple of assets
|
||||
"""
|
||||
assets = [{'asset_name': '', 'asset_id': '0'}]
|
||||
|
||||
assets_list = CaseAssets.query.with_entities(
|
||||
CaseAssets.asset_name,
|
||||
CaseAssets.asset_id,
|
||||
AssetsType.asset_name.label('type')
|
||||
).filter(
|
||||
CaseAssets.case_id == caseid
|
||||
).join(CaseAssets.asset_type).order_by(CaseAssets.asset_name).all()
|
||||
|
||||
for asset in assets_list:
|
||||
assets.append({
|
||||
'asset_name': "{} ({})".format(asset.asset_name, asset.type),
|
||||
'asset_id': asset.asset_id
|
||||
})
|
||||
|
||||
return assets
|
||||
|
||||
|
||||
def get_case_iocs_for_tm(caseid):
|
||||
iocs = [{'ioc_value': '', 'ioc_id': '0'}]
|
||||
|
||||
iocs_list = Ioc.query.with_entities(
|
||||
Ioc.ioc_value,
|
||||
Ioc.ioc_id
|
||||
).filter(
|
||||
IocLink.case_id == caseid
|
||||
).join(
|
||||
IocLink.ioc
|
||||
).order_by(
|
||||
Ioc.ioc_value
|
||||
).all()
|
||||
|
||||
for ioc in iocs_list:
|
||||
iocs.append({
|
||||
'ioc_value': "{}".format(ioc.ioc_value),
|
||||
'ioc_id': ioc.ioc_id
|
||||
})
|
||||
|
||||
return iocs
|
||||
|
||||
|
||||
def delete_event(event, caseid):
|
||||
delete_event_category(event.event_id)
|
||||
|
||||
CaseEventsAssets.query.filter(
|
||||
CaseEventsAssets.event_id == event.event_id,
|
||||
CaseEventsAssets.case_id == caseid
|
||||
).delete()
|
||||
|
||||
CaseEventsIoc.query.filter(
|
||||
CaseEventsIoc.event_id == event.event_id,
|
||||
CaseEventsIoc.case_id == caseid
|
||||
).delete()
|
||||
|
||||
com_ids = EventComments.query.with_entities(
|
||||
EventComments.comment_id
|
||||
).filter(
|
||||
EventComments.comment_event_id == event.event_id
|
||||
).all()
|
||||
|
||||
com_ids = [c.comment_id for c in com_ids]
|
||||
EventComments.query.filter(EventComments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
Comments.query.filter(Comments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
db.session.commit()
|
||||
|
||||
db.session.delete(event)
|
||||
update_timeline_state(caseid=caseid)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_category_by_name(cat_name):
|
||||
return EventCategory.query.filter(
|
||||
EventCategory.name == cat_name,
|
||||
).first()
|
||||
|
||||
|
||||
def get_default_category():
|
||||
return EventCategory.query.with_entities(
|
||||
EventCategory.id,
|
||||
EventCategory.name
|
||||
).filter(
|
||||
EventCategory.name == "Unspecified"
|
||||
).first()
|
||||
|
356
iris-web/source/app/datamgmt/case/case_iocs_db.py
Normal file
356
iris-web/source/app/datamgmt/case/case_iocs_db.py
Normal file
@ -0,0 +1,356 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# IRIS Source Code
|
||||
# Copyright (C) 2021 - Airbus CyberSecurity (SAS)
|
||||
# ir@cyberactionlab.net
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
from flask_login import current_user
|
||||
from sqlalchemy import and_
|
||||
|
||||
from app import db
|
||||
from app.datamgmt.states import update_ioc_state
|
||||
from app.iris_engine.access_control.utils import ac_get_fast_user_cases_access
|
||||
from app.models import CaseEventsIoc
|
||||
from app.models import Cases
|
||||
from app.models import Client
|
||||
from app.models import Comments
|
||||
from app.models import Ioc
|
||||
from app.models import IocAssetLink
|
||||
from app.models import IocComments
|
||||
from app.models import IocLink
|
||||
from app.models import IocType
|
||||
from app.models import Tlp
|
||||
from app.models.authorization import User
|
||||
|
||||
|
||||
def get_iocs(caseid):
|
||||
iocs = IocLink.query.with_entities(
|
||||
Ioc.ioc_value,
|
||||
Ioc.ioc_id,
|
||||
Ioc.ioc_uuid
|
||||
).filter(
|
||||
IocLink.case_id == caseid,
|
||||
IocLink.ioc_id == Ioc.ioc_id
|
||||
).all()
|
||||
|
||||
return iocs
|
||||
|
||||
|
||||
def get_ioc(ioc_id, caseid=None):
|
||||
if caseid:
|
||||
return IocLink.query.with_entities(
|
||||
Ioc
|
||||
).filter(and_(
|
||||
Ioc.ioc_id == ioc_id,
|
||||
IocLink.case_id == caseid
|
||||
)).join(
|
||||
IocLink.ioc
|
||||
).first()
|
||||
|
||||
return Ioc.query.filter(Ioc.ioc_id == ioc_id).first()
|
||||
|
||||
|
||||
def update_ioc(ioc_type, ioc_tags, ioc_value, ioc_description, ioc_tlp, userid, ioc_id):
|
||||
ioc = get_ioc(ioc_id)
|
||||
|
||||
if ioc:
|
||||
ioc.ioc_type = ioc_type
|
||||
ioc.ioc_tags = ioc_tags
|
||||
ioc.ioc_value = ioc_value
|
||||
ioc.ioc_description = ioc_description
|
||||
ioc.ioc_tlp_id = ioc_tlp
|
||||
ioc.user_id = userid
|
||||
|
||||
db.session.commit()
|
||||
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def delete_ioc(ioc, caseid):
|
||||
with db.session.begin_nested():
|
||||
IocLink.query.filter(
|
||||
and_(
|
||||
IocLink.ioc_id == ioc.ioc_id,
|
||||
IocLink.case_id == caseid
|
||||
)
|
||||
).delete()
|
||||
|
||||
res = IocLink.query.filter(
|
||||
IocLink.ioc_id == ioc.ioc_id,
|
||||
).all()
|
||||
|
||||
if res:
|
||||
return False
|
||||
|
||||
IocAssetLink.query.filter(
|
||||
IocAssetLink.ioc_id == ioc.ioc_id
|
||||
).delete()
|
||||
|
||||
CaseEventsIoc.query.filter(
|
||||
CaseEventsIoc.ioc_id == ioc.ioc_id
|
||||
).delete()
|
||||
|
||||
com_ids = IocComments.query.with_entities(
|
||||
IocComments.comment_id
|
||||
).filter(
|
||||
IocComments.comment_ioc_id == ioc.ioc_id
|
||||
).all()
|
||||
|
||||
com_ids = [c.comment_id for c in com_ids]
|
||||
IocComments.query.filter(IocComments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
Comments.query.filter(Comments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
db.session.delete(ioc)
|
||||
|
||||
update_ioc_state(caseid=caseid)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def get_detailed_iocs(caseid):
|
||||
detailed_iocs = IocLink.query.with_entities(
|
||||
Ioc.ioc_id,
|
||||
Ioc.ioc_uuid,
|
||||
Ioc.ioc_value,
|
||||
Ioc.ioc_type_id,
|
||||
IocType.type_name.label('ioc_type'),
|
||||
Ioc.ioc_type_id,
|
||||
Ioc.ioc_description,
|
||||
Ioc.ioc_tags,
|
||||
Ioc.ioc_misp,
|
||||
Tlp.tlp_name,
|
||||
Tlp.tlp_bscolor,
|
||||
Ioc.ioc_tlp_id
|
||||
).filter(
|
||||
and_(IocLink.case_id == caseid,
|
||||
IocLink.ioc_id == Ioc.ioc_id)
|
||||
).join(IocLink.ioc,
|
||||
Ioc.tlp,
|
||||
Ioc.ioc_type
|
||||
).order_by(IocType.type_name).all()
|
||||
|
||||
return detailed_iocs
|
||||
|
||||
|
||||
def get_ioc_links(ioc_id, caseid):
|
||||
search_condition = and_(Cases.case_id.in_([]))
|
||||
|
||||
user_search_limitations = ac_get_fast_user_cases_access(current_user.id)
|
||||
if user_search_limitations:
|
||||
search_condition = and_(Cases.case_id.in_(user_search_limitations))
|
||||
|
||||
ioc_link = IocLink.query.with_entities(
|
||||
Cases.case_id,
|
||||
Cases.name.label('case_name'),
|
||||
Client.name.label('client_name')
|
||||
).filter(and_(
|
||||
IocLink.ioc_id == ioc_id,
|
||||
IocLink.case_id != caseid,
|
||||
search_condition)
|
||||
).join(IocLink.case, Cases.client).all()
|
||||
|
||||
return ioc_link
|
||||
|
||||
|
||||
def find_ioc(ioc_value, ioc_type_id):
|
||||
ioc = Ioc.query.filter(Ioc.ioc_value == ioc_value,
|
||||
Ioc.ioc_type_id == ioc_type_id).first()
|
||||
|
||||
return ioc
|
||||
|
||||
|
||||
def add_ioc(ioc, user_id, caseid):
|
||||
if not ioc:
|
||||
return None, False
|
||||
|
||||
ioc.user_id = user_id
|
||||
|
||||
db_ioc = find_ioc(ioc.ioc_value, ioc.ioc_type_id)
|
||||
|
||||
if not db_ioc:
|
||||
db.session.add(ioc)
|
||||
|
||||
update_ioc_state(caseid=caseid)
|
||||
db.session.commit()
|
||||
return ioc, False
|
||||
|
||||
else:
|
||||
# IoC already exists
|
||||
return db_ioc, True
|
||||
|
||||
|
||||
def find_ioc_link(ioc_id, caseid):
|
||||
db_link = IocLink.query.filter(
|
||||
IocLink.case_id == caseid,
|
||||
IocLink.ioc_id == ioc_id
|
||||
).first()
|
||||
|
||||
return db_link
|
||||
|
||||
|
||||
def add_ioc_link(ioc_id, caseid):
|
||||
|
||||
db_link = find_ioc_link(ioc_id, caseid)
|
||||
if db_link:
|
||||
# Link already exists
|
||||
return True
|
||||
else:
|
||||
link = IocLink()
|
||||
link.case_id = caseid
|
||||
link.ioc_id = ioc_id
|
||||
|
||||
db.session.add(link)
|
||||
db.session.commit()
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_ioc_types_list():
|
||||
ioc_types = IocType.query.with_entities(
|
||||
IocType.type_id,
|
||||
IocType.type_name,
|
||||
IocType.type_description,
|
||||
IocType.type_taxonomy,
|
||||
IocType.type_validation_regex,
|
||||
IocType.type_validation_expect,
|
||||
).all()
|
||||
|
||||
l_types = [row._asdict() for row in ioc_types]
|
||||
return l_types
|
||||
|
||||
|
||||
def add_ioc_type(name:str, description:str, taxonomy:str):
|
||||
ioct = IocType(type_name=name,
|
||||
type_description=description,
|
||||
type_taxonomy=taxonomy
|
||||
)
|
||||
|
||||
db.session.add(ioct)
|
||||
db.session.commit()
|
||||
return ioct
|
||||
|
||||
|
||||
def check_ioc_type_id(type_id: int):
|
||||
type_id = IocType.query.filter(
|
||||
IocType.type_id == type_id
|
||||
).first()
|
||||
|
||||
return type_id
|
||||
|
||||
|
||||
def get_ioc_type_id(type_name: str):
|
||||
type_id = IocType.query.filter(
|
||||
IocType.type_name == type_name
|
||||
).first()
|
||||
|
||||
return type_id if type_id else None
|
||||
|
||||
|
||||
def get_tlps():
|
||||
return [(tlp.tlp_id, tlp.tlp_name) for tlp in Tlp.query.all()]
|
||||
|
||||
|
||||
def get_tlps_dict():
|
||||
tlpDict = {}
|
||||
for tlp in Tlp.query.all():
|
||||
tlpDict[tlp.tlp_name]=tlp.tlp_id
|
||||
return tlpDict
|
||||
|
||||
|
||||
def get_case_ioc_comments(ioc_id):
|
||||
return Comments.query.filter(
|
||||
IocComments.comment_ioc_id == ioc_id
|
||||
).with_entities(
|
||||
Comments
|
||||
).join(
|
||||
IocComments,
|
||||
Comments.comment_id == IocComments.comment_id
|
||||
).order_by(
|
||||
Comments.comment_date.asc()
|
||||
).all()
|
||||
|
||||
|
||||
def add_comment_to_ioc(ioc_id, comment_id):
|
||||
ec = IocComments()
|
||||
ec.comment_ioc_id = ioc_id
|
||||
ec.comment_id = comment_id
|
||||
|
||||
db.session.add(ec)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_case_iocs_comments_count(iocs_list):
|
||||
return IocComments.query.filter(
|
||||
IocComments.comment_ioc_id.in_(iocs_list)
|
||||
).with_entities(
|
||||
IocComments.comment_ioc_id,
|
||||
IocComments.comment_id
|
||||
).group_by(
|
||||
IocComments.comment_ioc_id,
|
||||
IocComments.comment_id
|
||||
).all()
|
||||
|
||||
|
||||
def get_case_ioc_comment(ioc_id, comment_id):
|
||||
return IocComments.query.filter(
|
||||
IocComments.comment_ioc_id == ioc_id,
|
||||
IocComments.comment_id == comment_id
|
||||
).with_entities(
|
||||
Comments.comment_id,
|
||||
Comments.comment_text,
|
||||
Comments.comment_date,
|
||||
Comments.comment_update_date,
|
||||
Comments.comment_uuid,
|
||||
User.name,
|
||||
User.user
|
||||
).join(
|
||||
IocComments.comment,
|
||||
Comments.user
|
||||
).first()
|
||||
|
||||
|
||||
def delete_ioc_comment(ioc_id, comment_id):
|
||||
comment = Comments.query.filter(
|
||||
Comments.comment_id == comment_id,
|
||||
Comments.comment_user_id == current_user.id
|
||||
).first()
|
||||
if not comment:
|
||||
return False, "You are not allowed to delete this comment"
|
||||
|
||||
IocComments.query.filter(
|
||||
IocComments.comment_ioc_id == ioc_id,
|
||||
IocComments.comment_id == comment_id
|
||||
).delete()
|
||||
|
||||
db.session.delete(comment)
|
||||
db.session.commit()
|
||||
|
||||
return True, "Comment deleted"
|
||||
|
||||
def get_ioc_by_value(ioc_value, caseid=None):
|
||||
if caseid:
|
||||
return IocLink.query.with_entities(
|
||||
Ioc
|
||||
).filter(and_(
|
||||
Ioc.ioc_value == ioc_value,
|
||||
IocLink.case_id == caseid
|
||||
)).join(
|
||||
IocLink.ioc
|
||||
).first()
|
||||
|
||||
return Ioc.query.filter(Ioc.ioc_value == ioc_value).first()
|
374
iris-web/source/app/datamgmt/case/case_notes_db.py
Normal file
374
iris-web/source/app/datamgmt/case/case_notes_db.py
Normal file
@ -0,0 +1,374 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# IRIS Source Code
|
||||
# Copyright (C) 2021 - Airbus CyberSecurity (SAS)
|
||||
# ir@cyberactionlab.net
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
from flask_login import current_user
|
||||
from sqlalchemy import and_
|
||||
|
||||
from app import db
|
||||
from app.datamgmt.manage.manage_attribute_db import get_default_custom_attributes
|
||||
from app.datamgmt.states import update_notes_state
|
||||
from app.models import Comments
|
||||
from app.models import Notes
|
||||
from app.models import NotesComments
|
||||
from app.models import NotesGroup
|
||||
from app.models import NotesGroupLink
|
||||
from app.models.authorization import User
|
||||
|
||||
|
||||
def get_note(note_id, caseid=None):
|
||||
note = Notes.query.with_entities(
|
||||
Notes.note_id,
|
||||
Notes.note_uuid,
|
||||
Notes.note_title,
|
||||
Notes.note_content,
|
||||
Notes.note_creationdate,
|
||||
Notes.note_lastupdate,
|
||||
NotesGroupLink.group_id,
|
||||
NotesGroup.group_title,
|
||||
NotesGroup.group_uuid,
|
||||
Notes.custom_attributes,
|
||||
Notes.note_case_id
|
||||
).filter(and_(
|
||||
Notes.note_id == note_id,
|
||||
Notes.note_case_id == caseid
|
||||
)).join(
|
||||
NotesGroupLink.note,
|
||||
NotesGroupLink.note_group
|
||||
).first()
|
||||
|
||||
return note
|
||||
|
||||
|
||||
def get_note_raw(note_id, caseid):
|
||||
note = Notes.query.filter(
|
||||
Notes.note_case_id == caseid,
|
||||
Notes.note_id == note_id
|
||||
).first()
|
||||
return note
|
||||
|
||||
|
||||
def delete_note(note_id, caseid):
|
||||
with db.session.begin_nested():
|
||||
NotesGroupLink.query.filter(and_(
|
||||
NotesGroupLink.note_id == note_id,
|
||||
NotesGroupLink.case_id == caseid
|
||||
)).delete()
|
||||
|
||||
com_ids = NotesComments.query.with_entities(
|
||||
NotesComments.comment_id
|
||||
).filter(
|
||||
NotesComments.comment_note_id == note_id
|
||||
).all()
|
||||
|
||||
com_ids = [c.comment_id for c in com_ids]
|
||||
NotesComments.query.filter(NotesComments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
Comments.query.filter(Comments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
Notes.query.filter(Notes.note_id == note_id).delete()
|
||||
|
||||
update_notes_state(caseid=caseid)
|
||||
|
||||
|
||||
def update_note(note_content, note_title, update_date, user_id, note_id, caseid):
|
||||
note = get_note_raw(note_id, caseid=caseid)
|
||||
|
||||
if note:
|
||||
note.note_content = note_content
|
||||
note.note_title = note_title
|
||||
note.note_lastupdate = update_date
|
||||
note.note_user = user_id
|
||||
|
||||
db.session.commit()
|
||||
return note
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def add_note(note_title, creation_date, user_id, caseid, group_id, note_content=""):
|
||||
note = Notes()
|
||||
note.note_title = note_title
|
||||
note.note_creationdate = note.note_lastupdate = creation_date
|
||||
note.note_content = note_content
|
||||
note.note_case_id = caseid
|
||||
note.note_user = user_id
|
||||
|
||||
note.custom_attributes = get_default_custom_attributes('note')
|
||||
db.session.add(note)
|
||||
|
||||
update_notes_state(caseid=caseid, userid=user_id)
|
||||
db.session.commit()
|
||||
|
||||
if note.note_id:
|
||||
ngl = NotesGroupLink()
|
||||
ngl.note_id = note.note_id
|
||||
ngl.group_id = group_id
|
||||
ngl.case_id = caseid
|
||||
|
||||
db.session.add(ngl)
|
||||
db.session.commit()
|
||||
|
||||
return note
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_groups_short(caseid):
|
||||
groups_short = NotesGroup.query.with_entities(
|
||||
NotesGroup.group_id,
|
||||
NotesGroup.group_uuid,
|
||||
NotesGroup.group_title
|
||||
).filter(
|
||||
NotesGroup.group_case_id == caseid
|
||||
).order_by(
|
||||
NotesGroup.group_id
|
||||
).all()
|
||||
|
||||
return groups_short
|
||||
|
||||
|
||||
def get_notes_from_group(caseid, group_id):
|
||||
notes = NotesGroupLink.query.with_entities(
|
||||
Notes.note_id,
|
||||
Notes.note_uuid,
|
||||
Notes.note_title,
|
||||
User.user,
|
||||
Notes.note_lastupdate
|
||||
).filter(
|
||||
NotesGroupLink.case_id == caseid,
|
||||
NotesGroupLink.group_id == group_id,
|
||||
).join(
|
||||
NotesGroupLink.note,
|
||||
Notes.user
|
||||
).order_by(
|
||||
Notes.note_id
|
||||
).all()
|
||||
|
||||
return notes
|
||||
|
||||
|
||||
def get_groups_detail(caseid):
|
||||
groups = NotesGroupLink.query.with_entities(
|
||||
NotesGroup.group_id,
|
||||
NotesGroup.group_uuid,
|
||||
NotesGroup.group_title,
|
||||
Notes.note_id,
|
||||
Notes.note_uuid,
|
||||
Notes.note_title,
|
||||
User.user,
|
||||
Notes.note_lastupdate
|
||||
).filter(
|
||||
NotesGroupLink.case_id == caseid,
|
||||
).join(
|
||||
NotesGroupLink.note,
|
||||
NotesGroupLink.note_group,
|
||||
Notes.user
|
||||
).group_by(
|
||||
NotesGroup.group_id,
|
||||
Notes.note_id,
|
||||
User.user
|
||||
).all()
|
||||
|
||||
return groups
|
||||
|
||||
|
||||
def get_group_details(group_id, caseid):
|
||||
group_l = NotesGroup.query.with_entities(
|
||||
NotesGroup.group_id,
|
||||
NotesGroup.group_uuid,
|
||||
NotesGroup.group_title,
|
||||
NotesGroup.group_creationdate,
|
||||
NotesGroup.group_lastupdate
|
||||
).filter(
|
||||
NotesGroup.group_case_id == caseid
|
||||
).filter(
|
||||
NotesGroup.group_id == group_id
|
||||
).first()
|
||||
|
||||
group = None
|
||||
if group_l:
|
||||
group = group_l._asdict()
|
||||
group['notes'] = [note._asdict() for note in get_notes_from_group(caseid=caseid, group_id=group_id)]
|
||||
|
||||
return group
|
||||
|
||||
|
||||
def add_note_group(group_title, caseid, userid, creationdate):
|
||||
ng = NotesGroup()
|
||||
ng.group_title = group_title
|
||||
ng.group_case_id = caseid
|
||||
ng.group_user = userid
|
||||
ng.group_creationdate = creationdate
|
||||
ng.group_lastupdate = creationdate
|
||||
|
||||
db.session.add(ng)
|
||||
|
||||
update_notes_state(caseid=caseid, userid=userid)
|
||||
db.session.commit()
|
||||
|
||||
if group_title == '':
|
||||
ng.group_title = "New notes group"
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return ng
|
||||
|
||||
|
||||
def delete_note_group(group_id, caseid):
|
||||
ngl = NotesGroupLink.query.with_entities(
|
||||
NotesGroupLink.note_id
|
||||
).filter(
|
||||
NotesGroupLink.group_id == group_id,
|
||||
NotesGroupLink.case_id == caseid
|
||||
).all()
|
||||
|
||||
if not ngl:
|
||||
group = NotesGroup.query.filter(and_(
|
||||
NotesGroup.group_id == group_id,
|
||||
NotesGroup.group_case_id == caseid
|
||||
)).first()
|
||||
if not group:
|
||||
return False
|
||||
|
||||
db.session.delete(group)
|
||||
|
||||
update_notes_state(caseid=caseid)
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
to_delete = [row.note_id for row in ngl]
|
||||
|
||||
NotesGroupLink.query.filter(
|
||||
NotesGroupLink.group_id == group_id,
|
||||
NotesGroupLink.case_id == caseid
|
||||
).delete()
|
||||
|
||||
db.session.commit()
|
||||
|
||||
for nid in to_delete:
|
||||
Notes.query.filter(Notes.note_id == nid).delete()
|
||||
|
||||
NotesGroup.query.filter(and_(
|
||||
NotesGroup.group_id == group_id,
|
||||
NotesGroup.group_case_id == caseid
|
||||
)).delete()
|
||||
|
||||
update_notes_state(caseid=caseid)
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
|
||||
def update_note_group(group_title, group_id, caseid):
|
||||
ng = NotesGroup.query.filter(and_(
|
||||
NotesGroup.group_id == group_id,
|
||||
NotesGroup.group_case_id == caseid
|
||||
)).first()
|
||||
|
||||
if ng:
|
||||
ng.group_title = group_title
|
||||
|
||||
update_notes_state(caseid=caseid)
|
||||
db.session.commit()
|
||||
return ng
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def find_pattern_in_notes(pattern, caseid):
|
||||
notes = Notes.query.filter(
|
||||
Notes.note_content.like(pattern),
|
||||
Notes.note_case_id == caseid
|
||||
).with_entities(
|
||||
Notes.note_id,
|
||||
Notes.note_title
|
||||
).all()
|
||||
|
||||
return notes
|
||||
|
||||
|
||||
def get_case_note_comments(note_id):
|
||||
return Comments.query.filter(
|
||||
NotesComments.comment_note_id == note_id
|
||||
).join(
|
||||
NotesComments,
|
||||
Comments.comment_id == NotesComments.comment_id
|
||||
).order_by(
|
||||
Comments.comment_date.asc()
|
||||
).all()
|
||||
|
||||
|
||||
def add_comment_to_note(note_id, comment_id):
|
||||
ec = NotesComments()
|
||||
ec.comment_note_id = note_id
|
||||
ec.comment_id = comment_id
|
||||
|
||||
db.session.add(ec)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_case_notes_comments_count(notes_list):
|
||||
return NotesComments.query.filter(
|
||||
NotesComments.comment_note_id.in_(notes_list)
|
||||
).with_entities(
|
||||
NotesComments.comment_note_id,
|
||||
NotesComments.comment_id
|
||||
).group_by(
|
||||
NotesComments.comment_note_id,
|
||||
NotesComments.comment_id
|
||||
).all()
|
||||
|
||||
|
||||
def get_case_note_comment(note_id, comment_id):
|
||||
return NotesComments.query.filter(
|
||||
NotesComments.comment_note_id == note_id,
|
||||
NotesComments.comment_id == comment_id
|
||||
).with_entities(
|
||||
Comments.comment_id,
|
||||
Comments.comment_text,
|
||||
Comments.comment_date,
|
||||
Comments.comment_update_date,
|
||||
Comments.comment_uuid,
|
||||
User.name,
|
||||
User.user
|
||||
).join(
|
||||
NotesComments.comment,
|
||||
Comments.user
|
||||
).first()
|
||||
|
||||
|
||||
def delete_note_comment(note_id, comment_id):
|
||||
comment = Comments.query.filter(
|
||||
Comments.comment_id == comment_id,
|
||||
Comments.comment_user_id == current_user.id
|
||||
).first()
|
||||
if not comment:
|
||||
return False, "You are not allowed to delete this comment"
|
||||
|
||||
NotesComments.query.filter(
|
||||
NotesComments.comment_note_id == note_id,
|
||||
NotesComments.comment_id == comment_id
|
||||
).delete()
|
||||
|
||||
db.session.delete(comment)
|
||||
db.session.commit()
|
||||
|
||||
return True, "Comment deleted"
|
174
iris-web/source/app/datamgmt/case/case_rfiles_db.py
Normal file
174
iris-web/source/app/datamgmt/case/case_rfiles_db.py
Normal file
@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# IRIS Source Code
|
||||
# Copyright (C) 2021 - Airbus CyberSecurity (SAS)
|
||||
# ir@cyberactionlab.net
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import datetime
|
||||
from flask_login import current_user
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import desc
|
||||
|
||||
from app import db
|
||||
from app.datamgmt.manage.manage_attribute_db import get_default_custom_attributes
|
||||
from app.datamgmt.states import update_evidences_state
|
||||
from app.models import CaseReceivedFile
|
||||
from app.models import Comments
|
||||
from app.models import EvidencesComments
|
||||
from app.models.authorization import User
|
||||
|
||||
|
||||
def get_rfiles(caseid):
|
||||
crf = CaseReceivedFile.query.with_entities(
|
||||
CaseReceivedFile.id,
|
||||
CaseReceivedFile.file_uuid,
|
||||
CaseReceivedFile.filename,
|
||||
CaseReceivedFile.date_added,
|
||||
CaseReceivedFile.file_hash,
|
||||
CaseReceivedFile.file_description,
|
||||
CaseReceivedFile.file_size,
|
||||
User.name.label('username')
|
||||
).filter(
|
||||
CaseReceivedFile.case_id == caseid
|
||||
).join(CaseReceivedFile.user).order_by(desc(CaseReceivedFile.date_added)).all()
|
||||
|
||||
return crf
|
||||
|
||||
|
||||
def add_rfile(evidence, caseid, user_id):
|
||||
|
||||
evidence.date_added = datetime.datetime.now()
|
||||
evidence.case_id = caseid
|
||||
evidence.user_id = user_id
|
||||
|
||||
evidence.custom_attributes = get_default_custom_attributes('evidence')
|
||||
|
||||
db.session.add(evidence)
|
||||
|
||||
update_evidences_state(caseid=caseid, userid=user_id)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return evidence
|
||||
|
||||
|
||||
def get_rfile(rfile_id, caseid):
|
||||
return CaseReceivedFile.query.filter(
|
||||
CaseReceivedFile.id == rfile_id,
|
||||
CaseReceivedFile.case_id == caseid
|
||||
).first()
|
||||
|
||||
|
||||
def update_rfile(evidence, user_id, caseid):
|
||||
|
||||
evidence.user_id = user_id
|
||||
|
||||
update_evidences_state(caseid=caseid, userid=user_id)
|
||||
db.session.commit()
|
||||
return evidence
|
||||
|
||||
|
||||
def delete_rfile(rfile_id, caseid):
|
||||
with db.session.begin_nested():
|
||||
com_ids = EvidencesComments.query.with_entities(
|
||||
EvidencesComments.comment_id
|
||||
).filter(
|
||||
EvidencesComments.comment_evidence_id == rfile_id
|
||||
).all()
|
||||
|
||||
com_ids = [c.comment_id for c in com_ids]
|
||||
EvidencesComments.query.filter(EvidencesComments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
Comments.query.filter(Comments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
CaseReceivedFile.query.filter(and_(
|
||||
CaseReceivedFile.id == rfile_id,
|
||||
CaseReceivedFile.case_id == caseid,
|
||||
)).delete()
|
||||
|
||||
update_evidences_state(caseid=caseid)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_case_evidence_comments(evidence_id):
|
||||
return Comments.query.filter(
|
||||
EvidencesComments.comment_evidence_id == evidence_id
|
||||
).join(
|
||||
EvidencesComments,
|
||||
Comments.comment_id == EvidencesComments.comment_id
|
||||
).order_by(
|
||||
Comments.comment_date.asc()
|
||||
).all()
|
||||
|
||||
|
||||
def add_comment_to_evidence(evidence_id, comment_id):
|
||||
ec = EvidencesComments()
|
||||
ec.comment_evidence_id = evidence_id
|
||||
ec.comment_id = comment_id
|
||||
|
||||
db.session.add(ec)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_case_evidence_comments_count(evidences_list):
|
||||
return EvidencesComments.query.filter(
|
||||
EvidencesComments.comment_evidence_id.in_(evidences_list)
|
||||
).with_entities(
|
||||
EvidencesComments.comment_evidence_id,
|
||||
EvidencesComments.comment_id
|
||||
).group_by(
|
||||
EvidencesComments.comment_evidence_id,
|
||||
EvidencesComments.comment_id
|
||||
).all()
|
||||
|
||||
|
||||
def get_case_evidence_comment(evidence_id, comment_id):
|
||||
return EvidencesComments.query.filter(
|
||||
EvidencesComments.comment_evidence_id == evidence_id,
|
||||
EvidencesComments.comment_id == comment_id
|
||||
).with_entities(
|
||||
Comments.comment_id,
|
||||
Comments.comment_text,
|
||||
Comments.comment_date,
|
||||
Comments.comment_update_date,
|
||||
Comments.comment_uuid,
|
||||
User.name,
|
||||
User.user
|
||||
).join(
|
||||
EvidencesComments.comment,
|
||||
Comments.user
|
||||
).first()
|
||||
|
||||
|
||||
def delete_evidence_comment(evidence_id, comment_id):
|
||||
comment = Comments.query.filter(
|
||||
Comments.comment_id == comment_id,
|
||||
Comments.comment_user_id == current_user.id
|
||||
).first()
|
||||
if not comment:
|
||||
return False, "You are not allowed to delete this comment"
|
||||
|
||||
EvidencesComments.query.filter(
|
||||
EvidencesComments.comment_evidence_id == evidence_id,
|
||||
EvidencesComments.comment_id == comment_id
|
||||
).delete()
|
||||
|
||||
db.session.delete(comment)
|
||||
db.session.commit()
|
||||
|
||||
return True, "Comment deleted"
|
335
iris-web/source/app/datamgmt/case/case_tasks_db.py
Normal file
335
iris-web/source/app/datamgmt/case/case_tasks_db.py
Normal file
@ -0,0 +1,335 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# IRIS Source Code
|
||||
# Copyright (C) 2021 - Airbus CyberSecurity (SAS)
|
||||
# ir@cyberactionlab.net
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 3 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
from datetime import datetime
|
||||
from flask_login import current_user
|
||||
from sqlalchemy import desc, and_
|
||||
|
||||
from app import db
|
||||
from app.datamgmt.manage.manage_attribute_db import get_default_custom_attributes
|
||||
from app.datamgmt.manage.manage_users_db import get_users_list_restricted_from_case
|
||||
from app.datamgmt.states import update_tasks_state
|
||||
from app.models import CaseTasks, TaskAssignee
|
||||
from app.models import Cases
|
||||
from app.models import Comments
|
||||
from app.models import TaskComments
|
||||
from app.models import TaskStatus
|
||||
from app.models.authorization import User
|
||||
|
||||
|
||||
def get_tasks_status():
|
||||
return TaskStatus.query.all()
|
||||
|
||||
|
||||
def get_tasks(caseid):
|
||||
return CaseTasks.query.with_entities(
|
||||
CaseTasks.id.label("task_id"),
|
||||
CaseTasks.task_uuid,
|
||||
CaseTasks.task_title,
|
||||
CaseTasks.task_description,
|
||||
CaseTasks.task_open_date,
|
||||
CaseTasks.task_tags,
|
||||
CaseTasks.task_status_id,
|
||||
TaskStatus.status_name,
|
||||
TaskStatus.status_bscolor
|
||||
).filter(
|
||||
CaseTasks.task_case_id == caseid
|
||||
).join(
|
||||
CaseTasks.status
|
||||
).order_by(
|
||||
desc(TaskStatus.status_name)
|
||||
).all()
|
||||
|
||||
|
||||
def get_tasks_with_assignees(caseid):
|
||||
tasks = get_tasks(caseid)
|
||||
if not tasks:
|
||||
return None
|
||||
|
||||
tasks = [c._asdict() for c in tasks]
|
||||
|
||||
task_with_assignees = []
|
||||
for task in tasks:
|
||||
task_id = task['task_id']
|
||||
get_assignee_list = TaskAssignee.query.with_entities(
|
||||
TaskAssignee.task_id,
|
||||
User.user,
|
||||
User.id,
|
||||
User.name
|
||||
).join(
|
||||
TaskAssignee.user
|
||||
).filter(
|
||||
TaskAssignee.task_id == task_id
|
||||
).all()
|
||||
|
||||
assignee_list = {}
|
||||
for member in get_assignee_list:
|
||||
if member.task_id not in assignee_list:
|
||||
|
||||
assignee_list[member.task_id] = [{
|
||||
'user': member.user,
|
||||
'name': member.name,
|
||||
'id': member.id
|
||||
}]
|
||||
else:
|
||||
assignee_list[member.task_id].append({
|
||||
'user': member.user,
|
||||
'name': member.name,
|
||||
'id': member.id
|
||||
})
|
||||
task['task_assignees'] = assignee_list.get(task['task_id'], [])
|
||||
task_with_assignees.append(task)
|
||||
|
||||
return task_with_assignees
|
||||
|
||||
|
||||
def get_task(task_id, caseid):
|
||||
return CaseTasks.query.filter(CaseTasks.id == task_id, CaseTasks.task_case_id == caseid).first()
|
||||
|
||||
|
||||
def get_task_with_assignees(task_id: int, case_id: int):
|
||||
"""
|
||||
Returns a task with its assignees
|
||||
|
||||
Args:
|
||||
task_id (int): Task ID
|
||||
case_id (int): Case ID
|
||||
|
||||
Returns:
|
||||
dict: Task with its assignees
|
||||
"""
|
||||
task = get_task(
|
||||
task_id=task_id,
|
||||
caseid=case_id
|
||||
)
|
||||
|
||||
if not task:
|
||||
return None
|
||||
|
||||
get_assignee_list = TaskAssignee.query.with_entities(
|
||||
TaskAssignee.task_id,
|
||||
User.user,
|
||||
User.id,
|
||||
User.name
|
||||
).join(
|
||||
TaskAssignee.user
|
||||
).filter(
|
||||
TaskAssignee.task_id == task_id
|
||||
).all()
|
||||
|
||||
assignee_list = {}
|
||||
for member in get_assignee_list:
|
||||
if member.task_id not in assignee_list:
|
||||
|
||||
assignee_list[member.task_id] = [{
|
||||
'user': member.user,
|
||||
'name': member.name,
|
||||
'id': member.id
|
||||
}]
|
||||
else:
|
||||
assignee_list[member.task_id].append({
|
||||
'user': member.user,
|
||||
'name': member.name,
|
||||
'id': member.id
|
||||
})
|
||||
|
||||
setattr(task, 'task_assignees', assignee_list.get(task.id, []))
|
||||
|
||||
return task
|
||||
|
||||
|
||||
def update_task_status(task_status, task_id, caseid):
|
||||
task = get_task(task_id, caseid)
|
||||
if task:
|
||||
try:
|
||||
task.task_status_id = task_status
|
||||
|
||||
update_tasks_state(caseid=caseid)
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def update_task_assignees(task, task_assignee_list, caseid):
|
||||
if not task:
|
||||
return None
|
||||
|
||||
cur_assignee_list = TaskAssignee.query.with_entities(
|
||||
TaskAssignee.user_id
|
||||
).filter(TaskAssignee.task_id == task.id).all()
|
||||
|
||||
# Some formatting
|
||||
set_cur_assignees = set([assignee[0] for assignee in cur_assignee_list])
|
||||
set_assignees = set(int(assignee) for assignee in task_assignee_list)
|
||||
|
||||
assignees_to_add = set_assignees - set_cur_assignees
|
||||
assignees_to_remove = set_cur_assignees - set_assignees
|
||||
|
||||
allowed_users = [u.get('user_id') for u in get_users_list_restricted_from_case(caseid)]
|
||||
|
||||
for uid in assignees_to_add:
|
||||
if uid not in allowed_users:
|
||||
continue
|
||||
|
||||
user = User.query.filter(User.id == uid).first()
|
||||
if user:
|
||||
ta = TaskAssignee()
|
||||
ta.task_id = task.id
|
||||
ta.user_id = user.id
|
||||
db.session.add(ta)
|
||||
|
||||
for uid in assignees_to_remove:
|
||||
TaskAssignee.query.filter(
|
||||
and_(TaskAssignee.task_id == task.id,
|
||||
TaskAssignee.user_id == uid)
|
||||
).delete()
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return task
|
||||
|
||||
|
||||
def add_task(task, assignee_id_list, user_id, caseid):
|
||||
now = datetime.now()
|
||||
task.task_case_id = caseid
|
||||
task.task_userid_open = user_id
|
||||
task.task_userid_update = user_id
|
||||
task.task_open_date = now
|
||||
task.task_last_update = now
|
||||
|
||||
task.custom_attributes = task.custom_attributes if task.custom_attributes else get_default_custom_attributes('task')
|
||||
|
||||
db.session.add(task)
|
||||
|
||||
update_tasks_state(caseid=caseid)
|
||||
db.session.commit()
|
||||
|
||||
update_task_status(task.task_status_id, task.id, caseid)
|
||||
update_task_assignees(task, assignee_id_list, caseid)
|
||||
|
||||
return task
|
||||
|
||||
|
||||
def get_case_task_comments(task_id):
|
||||
return Comments.query.filter(
|
||||
TaskComments.comment_task_id == task_id
|
||||
).join(
|
||||
TaskComments,
|
||||
Comments.comment_id == TaskComments.comment_id
|
||||
).order_by(
|
||||
Comments.comment_date.asc()
|
||||
).all()
|
||||
|
||||
|
||||
def add_comment_to_task(task_id, comment_id):
|
||||
ec = TaskComments()
|
||||
ec.comment_task_id = task_id
|
||||
ec.comment_id = comment_id
|
||||
|
||||
db.session.add(ec)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def get_case_tasks_comments_count(tasks_list):
|
||||
return TaskComments.query.filter(
|
||||
TaskComments.comment_task_id.in_(tasks_list)
|
||||
).with_entities(
|
||||
TaskComments.comment_task_id,
|
||||
TaskComments.comment_id
|
||||
).group_by(
|
||||
TaskComments.comment_task_id,
|
||||
TaskComments.comment_id
|
||||
).all()
|
||||
|
||||
|
||||
def get_case_task_comment(task_id, comment_id):
|
||||
return TaskComments.query.filter(
|
||||
TaskComments.comment_task_id == task_id,
|
||||
TaskComments.comment_id == comment_id
|
||||
).with_entities(
|
||||
Comments.comment_id,
|
||||
Comments.comment_text,
|
||||
Comments.comment_date,
|
||||
Comments.comment_update_date,
|
||||
Comments.comment_uuid,
|
||||
User.name,
|
||||
User.user
|
||||
).join(
|
||||
TaskComments.comment,
|
||||
Comments.user
|
||||
).first()
|
||||
|
||||
|
||||
def delete_task(task_id):
|
||||
with db.session.begin_nested():
|
||||
TaskAssignee.query.filter(
|
||||
TaskAssignee.task_id == task_id
|
||||
).delete()
|
||||
|
||||
com_ids = TaskComments.query.with_entities(
|
||||
TaskComments.comment_id
|
||||
).filter(
|
||||
TaskComments.comment_task_id == task_id
|
||||
).all()
|
||||
|
||||
com_ids = [c.comment_id for c in com_ids]
|
||||
TaskComments.query.filter(TaskComments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
Comments.query.filter(Comments.comment_id.in_(com_ids)).delete()
|
||||
|
||||
CaseTasks.query.filter(
|
||||
CaseTasks.id == task_id
|
||||
).delete()
|
||||
|
||||
|
||||
def delete_task_comment(task_id, comment_id):
|
||||
comment = Comments.query.filter(
|
||||
Comments.comment_id == comment_id,
|
||||
Comments.comment_user_id == current_user.id
|
||||
).first()
|
||||
if not comment:
|
||||
return False, "You are not allowed to delete this comment"
|
||||
|
||||
TaskComments.query.filter(
|
||||
TaskComments.comment_task_id == task_id,
|
||||
TaskComments.comment_id == comment_id
|
||||
).delete()
|
||||
|
||||
db.session.delete(comment)
|
||||
db.session.commit()
|
||||
|
||||
return True, "Comment deleted"
|
||||
|
||||
|
||||
def get_tasks_cases_mapping(open_cases_only=False):
|
||||
condition = Cases.close_date == None if open_cases_only else True
|
||||
|
||||
return CaseTasks.query.filter(
|
||||
condition
|
||||
).with_entities(
|
||||
CaseTasks.task_case_id,
|
||||
CaseTasks.task_status_id
|
||||
).join(
|
||||
CaseTasks.case
|
||||
).all()
|
Reference in New Issue
Block a user