Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NHUB-534] Implement section filters async #1077

Merged
merged 19 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
CYPRESS_SCREENSHOTS_FOLDER: /tmp/cypress
- name: Upload screenshots
if: ${{ failure() }}
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: screenshots-e2e
path: /tmp/cypress/**/*.png
2 changes: 1 addition & 1 deletion dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ six==1.16.0
# python-dateutil
sniffio==1.3.1
# via asgi-tools
superdesk-core @ git+https://github.com/superdesk/superdesk-core.git@async
superdesk-core @ git+https://github.com/superdesk/superdesk-core.git@hg/minor-improvements
# via -r requirements.txt
superdesk-planning @ git+https://github.com/superdesk/superdesk-planning.git@async
# via -r requirements.txt
Expand Down
3 changes: 3 additions & 0 deletions e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,8 @@
"build": "export NODE_ENV=production && webpack --progress --profile --colors",
"start": "webpack-dev-server --progress --colors --content-base dist --host 0.0.0.0",
"start-client-server": "http-server dist -p 8080 -s"
},
"volta": {
"node": "14.21.3"
}
}
19 changes: 5 additions & 14 deletions newsroom/cards/views.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import re

from pydantic import BaseModel, ValidationError
from pydantic import BaseModel

from superdesk.core import json
from superdesk.core.web import Request, Response, EndpointGroup
from superdesk.core.resources.fields import ObjectId as ObjectIdField

from newsroom.decorator import admin_only, login_required
from newsroom.utils import response_from_validation

from .model import CardResourceModel
from .service import CardsResourceService


Expand Down Expand Up @@ -57,11 +55,7 @@ async def create(request: Request) -> Response:
if not card_data.get("_id"):
card_data["_id"] = service.generate_id()

try:
new_card = CardResourceModel.model_validate(card_data)
new_ids = await service.create([new_card])
except ValidationError as error:
return response_from_validation(error)
new_ids = await service.create([card_data])

return Response({"success": True, "_id": new_ids[0]}, 201, ())

Expand All @@ -79,12 +73,9 @@ async def edit(args: CardItemUrlArgs, params: None, request: Request) -> Respons
if not card_data:
request.abort(400)

try:
await service.update(args.id, card_data, etag=request.get_header("If-Match"))
except ValidationError as error:
return response_from_validation(error)
await service.update(args.id, card_data, etag=request.get_header("If-Match"))

return Response({"success": True}, 200, ())
return Response({"success": True})


@cards_endpoints.endpoint("/cards/<id>", methods=["DELETE"])
Expand All @@ -99,4 +90,4 @@ async def delete(args: CardItemUrlArgs, params: None, request: Request) -> Respo

await service.delete(original, etag=request.get_header("If-Match"))

return Response({"success": True}, 200, ())
return Response({"success": True})
36 changes: 13 additions & 23 deletions newsroom/companies/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from datetime import datetime
from quart_babel import gettext
from werkzeug.exceptions import NotFound, BadRequest
from pydantic import BaseModel, ValidationError
from pydantic import BaseModel

from superdesk.core import get_app_config, get_current_app
from superdesk.core.web import Request, Response
Expand All @@ -17,14 +17,13 @@
get_public_user_data,
query_resource,
get_json_or_400_async,
response_from_validation,
success_response,
)
from newsroom.ui_config_async import UiConfigResourceService

from .module import company_endpoints, company_configs
from .utils import get_users_by_company
from .companies_async import CompanyService, CompanyResource
from .companies_async import CompanyService


def get_company_types_options():
Expand Down Expand Up @@ -69,7 +68,7 @@ async def search_companies(args: None, params: CompanySearchArgs, request: Reque
lookup = {"name": regex}
cursor = await CompanyService().search(lookup)
companies = await cursor.to_list_raw()
return Response(companies, 200, ())
return Response(companies)


@company_endpoints.endpoint("/companies/new", methods=["POST"])
Expand All @@ -82,13 +81,8 @@ async def create_company(request: Request) -> Response:
company_data = get_company_updates(company)
company_data["_id"] = ObjectId()

try:
new_company = CompanyResource.model_validate(company_data)
ids = await CompanyService().create([new_company])
except ValidationError as error:
return response_from_validation(error)

return Response({"success": True, "_id": ids[0]}, 201, ())
ids = await CompanyService().create([company_data])
return Response({"success": True, "_id": ids[0]}, 201)


def get_company_updates(data, original=None):
Expand Down Expand Up @@ -144,18 +138,14 @@ async def edit_company(args: CompanyItemArgs, params: None, request: Request) ->
if not original:
raise NotFound(gettext("Company not found"))
elif request.method == "GET":
return Response(original, 200, ())
return Response(original)

request_json = await get_json_or_400_async(request)
if not isinstance(request_json, dict):
return request.abort(400)

updates = get_company_updates(request_json, original)

try:
await service.update(args.company_id, updates)
except ValidationError as error:
return response_from_validation(error)
await service.update(args.company_id, updates)

return success_response({"success": True})

Expand All @@ -174,14 +164,14 @@ async def delete_company(args: CompanyItemArgs, params: None, request: Request)
try:
await UsersService().delete_many(lookup={"company": args.company_id})
except BadRequest as er:
return Response({"error": str(er)}, 403, ())
return Response({"error": str(er)}, 403)

try:
await service.delete(original)
except Exception as e:
return Response({"error": str(e)}, 400, ())
return Response({"error": str(e)}, 400)

return Response({"success": True}, 200, ())
return Response({"success": True})


@company_endpoints.endpoint("/companies/<string:company_id>/users", methods=["GET"])
Expand All @@ -193,7 +183,7 @@ async def company_users(args: CompanyItemArgs, params: None, request: Request) -
public_data = get_public_user_data(user.model_dump(by_alias=True))
users_list.append(public_data)

return Response(users_list, 200, ())
return Response(users_list)


@company_endpoints.endpoint("/companies/<string:company_id>/approve", methods=["POST"])
Expand All @@ -206,7 +196,7 @@ async def approve_company(args: CompanyItemArgs, params: None, request: Request)
if not original:
raise NotFound(gettext("Company not found"))
elif original.is_approved:
return Response({"error": gettext("Company is already approved")}, 403, ())
return Response({"error": gettext("Company is already approved")}, 403)

# Activate this Company
updates = {
Expand All @@ -221,4 +211,4 @@ async def approve_company(args: CompanyItemArgs, params: None, request: Request)
async for user in company_users:
await UsersService().approve_user(user)

return Response({"success": True}, 200, ())
return Response({"success": True})
12 changes: 11 additions & 1 deletion newsroom/factory/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from flask_mail import Mail
from flask_caching import Cache
from elasticapm.contrib.flask import ElasticAPM
from pydantic import ValidationError

from superdesk.flask import jsonify, request, render_template, g
from superdesk.storage import AmazonMediaStorage, SuperdeskGridFSMediaStorage
Expand All @@ -31,7 +32,7 @@
import newsroom
from newsroom.auth import SessionAuth
from newsroom.exceptions import AuthorizationError
from newsroom.utils import is_json_request
from newsroom.utils import is_json_request, parse_validation_error
from newsroom.gettext import setup_babel


Expand Down Expand Up @@ -214,11 +215,20 @@ def superdesk_api_error(err):
async def authorization_error(err: AuthorizationError):
return await render_template("authorization_error.html", message=err.message), err.code

def handle_validation_error(error: ValidationError):
"""
Gets the ValidationException error raised from Core framework's models/services, parses and returns it
to the client in a valid json format.
"""
errors = parse_validation_error(error)
return jsonify(errors), 400

self.register_error_handler(AssertionError, assertion_error)
self.register_error_handler(404, render_404)
self.register_error_handler(403, render_403)
self.register_error_handler(SuperdeskApiError, superdesk_api_error)
self.register_error_handler(AuthorizationError, authorization_error)
self.register_error_handler(ValidationError, handle_validation_error)

def general_setting(
self,
Expand Down
4 changes: 3 additions & 1 deletion newsroom/news_api/section_filters/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import superdesk
from newsroom.section_filters import SectionFiltersService, SectionFiltersResource

from newsroom.section_filters.section_filters import SectionFiltersService, SectionFiltersResource


# TODO-ASYNC: remove this once news_api modules are migrate to async
def init_app(app):
superdesk.register_resource("section_filters", NewsAPISectionFilterResource, SectionFiltersService, _app=app)

Expand Down
12 changes: 6 additions & 6 deletions newsroom/oauth_clients/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ async def search(args: None, params: ClientSearchArgs, request: Request) -> Resp
lookup = {"name": regex}
cursor = await ClientService().search(lookup)
data = await cursor.to_list_raw()
return Response(data, 200, ())
return Response(data)


@clients_endpoints.endpoint("/oauth_clients/new", methods=["POST"])
Expand Down Expand Up @@ -72,7 +72,7 @@ async def create(request: Request) -> Response:
(),
)

return Response({"success": True, "_id": ids[0], "password": password}, 201, ())
return Response({"success": True, "_id": ids[0], "password": password}, 201)


@clients_endpoints.endpoint("/oauth_clients/<string:client_id>", methods=["GET", "POST"])
Expand All @@ -86,7 +86,7 @@ async def edit(args: ClientArgs, params: None, request: Request) -> Response:
if not original:
return NotFound(gettext("Client not found"))
elif request.method == "GET":
return Response(original, 200, ())
return Response(original)

request_json = await get_json_or_400_async(request)
if not isinstance(request_json, dict):
Expand All @@ -95,7 +95,7 @@ async def edit(args: ClientArgs, params: None, request: Request) -> Response:
updates = {}
updates["name"] = request_json.get("name")
await service.update(args.client_id, updates)
return Response({"success": True}, 200, ())
return Response({"success": True})


@clients_endpoints.endpoint("/oauth_clients/<string:client_id>", methods=["DELETE"])
Expand All @@ -112,5 +112,5 @@ async def delete(args: ClientArgs, params: None, request: Request) -> Response:
try:
await service.delete(original)
except Exception as e:
return Response({"error": str(e)}, 400, ())
return Response({"success": True}, 200, ())
return Response({"error": str(e)}, 400)
return Response({"success": True})
21 changes: 8 additions & 13 deletions newsroom/section_filters/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
from quart_babel import lazy_gettext
import superdesk
from superdesk.flask import Blueprint
from .model import SectionFilter
from .service import SectionFiltersService

from .section_filters import SectionFiltersResource, SectionFiltersService
from .module import module # noqa

blueprint = Blueprint("section_filters", __name__)

from . import views # noqa
__all__ = ["SectionFilter", "SectionFiltersService"]


def init_app(app):
# TODO-Async: Remove this once agenda, news_api.news, search and wire are migrated to async
import superdesk
from .section_filters import SectionFiltersResource, SectionFiltersService

superdesk.register_resource("section_filters", SectionFiltersResource, SectionFiltersService, _app=app)
app.settings_app(
"section-filters",
lazy_gettext("Section Filters"),
weight=450,
data=views.get_settings_data,
)
12 changes: 12 additions & 0 deletions newsroom/section_filters/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from typing import Optional
from newsroom.core.resources.model import NewshubResourceModel


class SectionFilter(NewshubResourceModel):
name: str
description: str = ""
sd_product_id: Optional[str] = None
query: Optional[str] = None
is_enabled: bool = True
filter_type: str = "wire"
search_type: str = "wire"
45 changes: 45 additions & 0 deletions newsroom/section_filters/module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from quart_babel import lazy_gettext

from newsroom import MONGO_PREFIX
from newsroom.web.factory import NewsroomWebApp
from superdesk.core.module import Module
from superdesk.core.resources import ResourceConfig, MongoIndexOptions, MongoResourceConfig

from .model import SectionFilter
from .service import SectionFiltersService
from .views import get_settings_data, section_filters_endpoints

section_filters_config = ResourceConfig(
name="section_filters",
data_class=SectionFilter,
service=SectionFiltersService,
mongo=MongoResourceConfig(
prefix=MONGO_PREFIX,
indexes=[
MongoIndexOptions(
name="name",
keys=[("name", 1)],
unique=True,
collation={"locale": "en", "strength": 2},
)
],
),
default_sort=[("name", 1)],
)


def init_module(app: NewsroomWebApp):
app.wsgi.settings_app(
"section-filters",
lazy_gettext("Section Filters"),
weight=450,
data=get_settings_data,
devketanpro marked this conversation as resolved.
Show resolved Hide resolved
)


module = Module(
name="newsroom.section_filters",
resources=[section_filters_config],
endpoints=[section_filters_endpoints],
init=init_module,
)
Loading
Loading