Skip to content

Commit

Permalink
Merge branch 'hotfix/2.6.3' into release/2.7
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkLark86 committed Feb 19, 2024
2 parents 234037f + da528c6 commit abb4e56
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 3 deletions.
3 changes: 3 additions & 0 deletions client/actions/events/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,9 @@ const createEventFromPlanning = (plan: IPlanningItem) => (
if (plan.languages != null) {
newEvent.languages = plan.languages;
}
if (plan.priority != null) {
newEvent.priority = plan.priority;
}

const fieldsToConvert: Array<[keyof IPlanningItem, keyof IEventItem]> = [
['description_text', 'definition_short'],
Expand Down
2 changes: 1 addition & 1 deletion client/components/Events/EventItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class EventItemComponent extends React.Component<IProps, IState> {

return (
<div>
<Menu items={itemActions}>
<Menu zIndex={1050} items={itemActions}>
{
(toggle) => (
<div
Expand Down
2 changes: 1 addition & 1 deletion client/components/Planning/PlanningItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class PlanningItemComponent extends React.Component<IProps, IState> {

return (
<div>
<Menu items={itemActions}>
<Menu zIndex={1050} items={itemActions}>
{
(toggle) => (
<div
Expand Down
3 changes: 3 additions & 0 deletions client/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
IVocabulary,
IVocabularyItem,
RICH_FORMATTING_OPTION,
IVocabularyItem,

Check failure on line 13 in client/interfaces.ts

View workflow job for this annotation

GitHub Actions / client (14.x)

'IVocabularyItem' is already defined
} from 'superdesk-api';
import {Dispatch, Store} from 'redux';
import * as moment from 'moment';
Expand Down Expand Up @@ -1384,6 +1385,8 @@ export interface ISearchParams {
coverage_user_id?:string;
priority?: Array<number>;

priority?: Array<number>;

// Event Params
reference?: string;
location?: IEventLocation;
Expand Down
40 changes: 40 additions & 0 deletions client/utils/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,45 @@ function getFlattenedEventsByDate(events: Array<IEventItem>, startDate: moment.M
}


const getStartDate = (event: IEventItem) => (
event.dates?.all_day ? moment.utc(event.dates.start) : moment(event.dates?.start)
);

const getEndDate = (event: IEventItem) => (
(event.dates?.all_day || event.dates?.no_end_time) ? moment.utc(event.dates.end) : moment(event.dates?.end)
);

const isEventInRange = (
event: IEventItem,
eventStart: moment.Moment,
eventEnd: moment.Moment,
start: moment.Moment,
end?: moment.Moment,
) => {
let localStart = eventStart;
let localEnd = eventEnd;
let startUnit : moment.unitOfTime.StartOf = 'second';
let endUnit : moment.unitOfTime.StartOf = 'second';

if (event.dates?.all_day) {
// we have only dates in utc
localStart = moment(eventStart.format('YYYY-MM-DD'));
localEnd = moment(eventEnd.format('YYYY-MM-DD'));
startUnit = 'day';
endUnit = 'day';
}

if (event.dates?.no_end_time) {
// we have time for start, but only date for end
localStart = moment(eventStart);
localEnd = moment(eventEnd.format('YYYY-MM-DD'));
endUnit = 'day';
}

return localEnd.isSameOrAfter(start, endUnit) && (end == null || localStart.isSameOrBefore(end, startUnit));
};


const getStartDate = (event: IEventItem) => (

Check failure on line 900 in client/utils/events.ts

View workflow job for this annotation

GitHub Actions / client (14.x)

'getStartDate' is already defined
event.dates?.all_day ? moment.utc(event.dates.start) : moment(event.dates?.start)
);
Expand Down Expand Up @@ -1162,6 +1201,7 @@ function defaultEventValues(
if (defaultPlaceList) {
newEvent.place = defaultPlaceList;
}

return newEvent;
}

Expand Down
2 changes: 1 addition & 1 deletion e2e/server/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
-r ./core-requirements.txt
-e ../../
-e ../../
1 change: 1 addition & 0 deletions server/planning/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from .delete_marked_assignments import DeleteMarkedAssignments # noqa
from .export_to_newsroom import ExportToNewsroom # noqa
from .export_scheduled_filters import ExportScheduledFilters # noqa
from .purge_expired_locks import PurgeExpiredLocks # noqa
145 changes: 145 additions & 0 deletions server/planning/commands/purge_expired_locks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# -*- coding: utf-8; -*-
#
# This file is part of Superdesk.
#
# Copyright 2024 Sourcefabric z.u. and contributors.
#
# For the full copyright and license information, please see the
# AUTHORS and LICENSE files distributed with this source code, or
# at https://www.sourcefabric.org/superdesk/license

import logging

from flask import current_app as app
from eve.utils import date_to_str

from superdesk import Command, command, get_resource_service, Option
from superdesk.utc import utcnow
from superdesk.lock import lock, unlock
from superdesk.celery_task_utils import get_lock_id
from planning.item_lock import LOCK_ACTION, LOCK_SESSION, LOCK_TIME, LOCK_USER

logger = logging.getLogger(__name__)


class PurgeExpiredLocks(Command):
"""
Purge item locks that are linked to a non-existing session
resource: The name of the resource to purge item locks for
Example:
::
$ python manage.py planning:purge_expired_locks -r events
$ python manage.py planning:purge_expired_locks -r planning
$ python manage.py planning:purge_expired_locks -r assignments
"""

option_list = [Option("--resource", "-r", required=True)]

def run(self, resource: str):
logger.info("Starting to purge expired item locks")

lock_name = get_lock_id("purge_expired_locks", resource)
if not lock(lock_name, expire=600):
logger.info("purge expired locks task is already running")
return

try:
self._purge_item_locks(resource)
except Exception as err:
logger.exception(f"Failed to purge item locks ({err})")
finally:
unlock(lock_name)

logger.info("Completed purging expired item locks")

def _purge_item_locks(self, resource: str):
resource_service = get_resource_service(resource)
try:
autosave_service = get_resource_service(
"event_autosave" if resource == "events" else f"{resource}_autosave"
)
except KeyError:
autosave_service = None

for items in self.get_locked_items(resource):
failed_ids = []
for item in items:
try:
item_id = item["_id"]
except KeyError:
logger.exception("Item ID not found, unable to purge its lock")
continue

try:
# Remove all lock information from this item
resource_service.system_update(
item_id,
{
LOCK_USER: None,
LOCK_ACTION: None,
LOCK_SESSION: None,
LOCK_TIME: None,
},
item,
push_notification=False,
)
except Exception as err:
logger.exception(f"Failed to purge item lock ({err})")
failed_ids.append(item_id)
continue

if autosave_service is None:
continue

try:
# Delete any autosave items associated with this item
autosave_service.delete_action(lookup={"_id": item_id})
except Exception as err:
logger.exception(f"Failed to delete autosave item(s) ({err})")

num_items = len(items)
num_success = num_items - len(failed_ids)
if num_success != num_items:
logger.warning(f"{num_success}/{num_items} item locks purged. Failed IDs: {failed_ids}")
else:
logger.info(f"{num_items} item locks purged")

def get_locked_items(self, resource: str):
now = utcnow()
active_sessions = [str(session["_id"]) for session in get_resource_service("auth").get(req=None, lookup={})]
service = get_resource_service(resource)
total_received = 0
query = {
"query": {
"bool": {
"filter": [
{"exists": {"field": LOCK_SESSION}},
# Use a range filter for lock time, so if this task takes a while
# it will exclude any newer item locks and/or sessions
{"range": {LOCK_TIME: {"lt": date_to_str(now)}}},
],
"must_not": [
{"terms": {LOCK_SESSION: active_sessions}},
],
},
},
"size": app.config["MAX_EXPIRY_QUERY_LIMIT"],
"sort": [{LOCK_TIME: "asc"}],
}

for i in range(app.config["MAX_EXPIRY_LOOPS"]):
query["from"] = total_received
results = list(service.search(query))
num_results = len(results)

if not num_results:
break

total_received += num_results
yield results


command("planning:purge_expired_locks", PurgeExpiredLocks())

0 comments on commit abb4e56

Please sign in to comment.