<commit_before># This file is part of Indico.
# Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
#
# Indico is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# Indico 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Indico; if not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

from flask import session

from indico.core import signals
from indico.core.db import db
from indico.core.db.sqlalchemy.util.session import no_autoflush
from indico.modules.events.contributions import logger
from indico.modules.events.contributions.models.subcontributions import SubContribution
from indico.modules.events.contributions.models.contributions import Contribution
from indico.modules.events.logs.models.entries import EventLogRealm, EventLogKind
from indico.modules.events.timetable.models.entries import TimetableEntryType
from indico.modules.events.timetable.operations import (create_timetable_entry, update_timetable_entry,
                                                        delete_timetable_entry)


def _ensure_consistency(contrib):
    """Unschedule contribution if not consistent with timetable

    A contribution that has no session assigned, may not be scheduled
    inside a session.  A contribution that has a session assigned may
    only be scheduled inside a session block associated with that
    session, and that session block must match the session block of
    the contribution.

    :return: A bool indicating whether the contribution has been
             unscheduled to preserve consistency.
    """
    entry = contrib.timetable_entry
    if entry is None:
        return False
    if entry.parent_id is None and (contrib.session is not None or contrib.session_block is not None):
        # Top-level entry but we have a session/block set
        delete_timetable_entry(entry, log=False)
        return True
    elif entry.parent_id is not None:
        parent = entry.parent
        # Nested entry but no or a different session/block set
        if parent.session_block.session != contrib.session or parent.session_block != contrib.session_block:
            delete_timetable_entry(entry, log=False)
            return True
    return False


def _set_custom_fields(contrib, custom_fields_data):
    for custom_field_name, custom_field_value in custom_fields_data.iteritems():
        custom_field_id = int(custom_field_name[7:])  # Remove the 'custom_' part
        contrib.set_custom_field(custom_field_id, custom_field_value)


def create_contribution(event, contrib_data, custom_fields_data):
    start_dt = contrib_data.pop('start_date', None)
    contrib = Contribution(event_new=event)
    contrib.populate_from_dict(contrib_data)
    if start_dt is not None:
        create_timetable_entry(event, {'type': TimetableEntryType.CONTRIBUTION, 'start_dt': start_dt,
                                       'contribution': contrib})
    _set_custom_fields(contrib, custom_fields_data)
    db.session.flush()
    signals.event.contribution_created.send(contrib)
    logger.info('Contribution %s created by %s', contrib, session.user)
    contrib.event_new.log(EventLogRealm.management, EventLogKind.positive, 'Contributions',
                          'Contribution "{}" has been created'.format(contrib.title), session.user)
    return contrib


@no_autoflush
def update_contribution(contrib, contrib_data, custom_fields_data):
    """Update a contribution

    :param contrib: The `Contribution` to update
    :param data: A dict containing the data to update
    :return: A dictionary containing information related to the
             update.  `unscheduled` will be true if the modification
             resulted in the contribution being unscheduled.  In this
             case `undo_unschedule` contains the necessary data to
             re-schedule it (undoing the session change causing it to
             be unscheduled)
    """
    rv = {'unscheduled': False, 'undo_unschedule': None}
    current_session_block = contrib.session_block
    start_dt = contrib_data.pop('start_date', None)
    if start_dt is not None:
        update_timetable_entry(contrib.timetable_entry, {'start_dt': start_dt})
    contrib.populate_from_dict(contrib_data)
    _set_custom_fields(contrib, custom_fields_data)
    if 'session' in contrib_data:
        timetable_entry = contrib.timetable_entry
        if timetable_entry is not None and _ensure_consistency(contrib):
            rv['unscheduled'] = True
            rv['undo_unschedule'] = {'start_dt': timetable_entry.start_dt.isoformat(),
                                     'contribution_id': contrib.id,
                                     'session_block_id': current_session_block.id if current_session_block else None,
                                     'force': True}
    db.session.flush()<commit_msg>Make custom_fields_data optional in contrib ops<commit_after># This file is part of Indico.
# Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
#
# Indico is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# Indico 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Indico; if not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

from flask import session

from indico.core import signals
from indico.core.db import db
from indico.core.db.sqlalchemy.util.session import no_autoflush
from indico.modules.events.contributions import logger
from indico.modules.events.contributions.models.subcontributions import SubContribution
from indico.modules.events.contributions.models.contributions import Contribution
from indico.modules.events.logs.models.entries import EventLogRealm, EventLogKind
from indico.modules.events.timetable.models.entries import TimetableEntryType
from indico.modules.events.timetable.operations import (create_timetable_entry, update_timetable_entry,
                                                        delete_timetable_entry)


def _ensure_consistency(contrib):
    """Unschedule contribution if not consistent with timetable

    A contribution that has no session assigned, may not be scheduled
    inside a session.  A contribution that has a session assigned may
    only be scheduled inside a session block associated with that
    session, and that session block must match the session block of
    the contribution.

    :return: A bool indicating whether the contribution has been
             unscheduled to preserve consistency.
    """
    entry = contrib.timetable_entry
    if entry is None:
        return False
    if entry.parent_id is None and (contrib.session is not None or contrib.session_block is not None):
        # Top-level entry but we have a session/block set
        delete_timetable_entry(entry, log=False)
        return True
    elif entry.parent_id is not None:
        parent = entry.parent
        # Nested entry but no or a different session/block set
        if parent.session_block.session != contrib.session or parent.session_block != contrib.session_block:
            delete_timetable_entry(entry, log=False)
            return True
    return False


def _set_custom_fields(contrib, custom_fields_data):
    for custom_field_name, custom_field_value in custom_fields_data.iteritems():
        custom_field_id = int(custom_field_name[7:])  # Remove the 'custom_' part
        contrib.set_custom_field(custom_field_id, custom_field_value)


def create_contribution(event, contrib_data, custom_fields_data=None):
    start_dt = contrib_data.pop('start_date', None)
    contrib = Contribution(event_new=event)
    contrib.populate_from_dict(contrib_data)
    if start_dt is not None:
        create_timetable_entry(event, {'type': TimetableEntryType.CONTRIBUTION, 'start_dt': start_dt,
                                       'contribution': contrib})
    if custom_fields_data:
        _set_custom_fields(contrib, custom_fields_data)
    db.session.flush()
    signals.event.contribution_created.send(contrib)
    logger.info('Contribution %s created by %s', contrib, session.user)
    contrib.event_new.log(EventLogRealm.management, EventLogKind.positive, 'Contributions',
                          'Contribution "{}" has been created'.format(contrib.title), session.user)
    return contrib


@no_autoflush
def update_contribution(contrib, contrib_data, custom_fields_data=None):
    """Update a contribution

    :param contrib: The `Contribution` to update
    :param contrib_data: A dict containing the data to update
    :param custom_fields_data: A dict containing the data for custom
                               fields.
    :return: A dictionary containing information related to the
             update.  `unscheduled` will be true if the modification
             resulted in the contribution being unscheduled.  In this
             case `undo_unschedule` contains the necessary data to
             re-schedule it (undoing the session change causing it to
             be unscheduled)
    """
    rv = {'unscheduled': False, 'undo_unschedule': None}
    current_session_block = contrib.session_block
    start_dt = contrib_data.pop('start_date', None)
    if start_dt is not None:
        update_timetable_entry(contrib.timetable_entry, {'start_dt': start_dt})
    contrib.populate_from_dict(contrib_data)
    if custom_fields_data:
        _set_custom_fields(contrib, custom_fields_data)
    if 'session' in contrib_data:
        timetable_entry = contrib.timetable_entry
        if timetable_entry is not None and _ensure_consistency(contrib):
            rv['unscheduled'] = True
            rv['undo_unschedule'] = {'start_dt': timetable_entry.start_dt.isoformat(),
                                     'contribution_id': contrib.id,
                                     'session_block_id': current_session_block.id if current_session_block else None,
                                     'force': True}
    db.session.flush()
{'fraction_non_alphanumeric': 0.06605521586066333, 'fraction_numerical': 0.0018528812303131369, 'mean_word_length': 3.2837301587301586, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2361332', 'n_tokens_mistral': 2952, 'n_tokens_neox': 2791, 'n_words': 944}