<commit_before>"""
Actions manager for transcripts ajax calls.
+++++++++++++++++++++++++++++++++++++++++++

Module do not support rollback (pressing "Cancel" button in Studio)
All user changes are saved immediately.
"""
import copy
import os
import logging
import json
import requests

from django.http import HttpResponse, Http404
from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required
from django.conf import settings
from django.utils.translation import ugettext as _

from xmodule.contentstore.content import StaticContent
from xmodule.exceptions import NotFoundError
from xmodule.modulestore.django import modulestore, loc_mapper
from xmodule.contentstore.django import contentstore
from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError, InsufficientSpecificationError

from util.json_request import JsonResponse
from xmodule.modulestore.locator import BlockUsageLocator

from xmodule.video_module.transcripts_utils import (
    generate_subs_from_source,
    generate_srt_from_sjson, remove_subs_from_store,
    download_youtube_subs, get_transcripts_from_youtube,
    copy_or_rename_transcript,
    manage_video_subtitles_save,
    TranscriptsGenerationException,
    GetTranscriptsFromYouTubeException,
    TranscriptsRequestValidationException
)

from .access import has_course_access

__all__ = [
    'upload_transcripts',
    'download_transcripts',
    'check_transcripts',
    'choose_transcripts',
    'replace_transcripts',
    'rename_transcripts',
    'save_transcripts',
]

log = logging.getLogger(__name__)


def error_response(response, message, status_code=400):
    """
    Simplify similar actions: log message and return JsonResponse with message included in response.

    By default return 400 (Bad Request) Response.
    """
    log.debug(message)
    response['status'] = message
    return JsonResponse(response, status_code)


@login_required
def upload_transcripts(request):
    """
    Upload transcripts for current module.

    returns: response dict::

        status: 'Success' and HTTP 200 or 'Error' and HTTP 400.
        subs: Value of uploaded and saved html5 sub field in video item.
    """
    response = {
        'status': 'Unknown server error',
        'subs': '',
    }

    locator = request.POST.get('locator')
    if not locator:
        return error_response(response, 'POST data without "locator" form data.')

    try:
        item = _get_item(request, request.POST)
    except (ItemNotFoundError, InvalidLocationError, InsufficientSpecificationError):
        return error_response(response, "Can't find item by locator.")

    if 'file' not in request.FILES:
        return error_response(response, 'POST data without "file" form data.')

    video_list = request.POST.get('video_list')
    if not video_list:
        return error_response(response, 'POST data without video names.')

    try:
        video_list = json.loads(video_list)
    except ValueError:
        return error_response(response, 'Invalid video_list JSON.')

    source_subs_filedata = request.FILES['file'].read().decode('utf8')
    source_subs_filename = request.FILES['file'].name

    if '.' not in source_subs_filename:
        return error_response(response, "Undefined file extension.")

    basename = os.path.basename(source_subs_filename)
    source_subs_name = os.path.splitext(basename)[0]
    source_subs_ext = os.path.splitext(basename)[1][1:]

    if item.category != 'video':
        return error_response(response, 'Transcripts are supported only for "video" modules.')

    # Allow upload only if any video link is presented
    if video_list:
        sub_attr = source_subs_name

        try:  # Generate and save for 1.0 speed, will create subs_sub_attr.srt.sjson subtitles file in storage.
            generate_subs_from_source({1: sub_attr}, source_subs_ext, source_subs_filedata, item)
        except TranscriptsGenerationException as e:
            return error_response(response, e.message)
        statuses = {}
        for video_dict in video_list:
            video_name = video_dict['video']
            # We are creating transcripts for every video source,
            # for the case that in future, some of video sources can be deleted.
            statuses[video_name] = copy_or_rename_transcript(video_name, sub_attr, item, user=request.user)
            try:
                # updates item.sub with `video_name` if it is successful.
                copy_or_rename_transcript(video_name, sub_attr, item, user=request.user)
                selected_name = video_name  # name to write to item.sub field, chosen at random.
            except NotFoundError:
                # subtitles file `sub_attr` is not presented in the system. Nothing to copy or rename.
                return error_response(response, "Can't find transcripts in storage for {}".format(sub_attr))

        item.sub = selected_name  # write one of  new subtitles names to item.sub attribute.
        item.save_with_metadata(request.user)
        response['subs'] = item.sub
        response['status'] = 'Success'
    else:
        return error_response(response, 'Empty video sources.')

    return JsonResponse(response)


@login_required
def download_transcripts(request):
    """
    Passes to user requested transcripts file.

    Raises Http404 if unsuccessful.
    """<commit_msg>Remove duplicate code in transcripts_ajax.<commit_after>"""
Actions manager for transcripts ajax calls.
+++++++++++++++++++++++++++++++++++++++++++

Module do not support rollback (pressing "Cancel" button in Studio)
All user changes are saved immediately.
"""
import copy
import os
import logging
import json
import requests

from django.http import HttpResponse, Http404
from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required
from django.conf import settings
from django.utils.translation import ugettext as _

from xmodule.contentstore.content import StaticContent
from xmodule.exceptions import NotFoundError
from xmodule.modulestore.django import modulestore, loc_mapper
from xmodule.contentstore.django import contentstore
from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError, InsufficientSpecificationError

from util.json_request import JsonResponse
from xmodule.modulestore.locator import BlockUsageLocator

from xmodule.video_module.transcripts_utils import (
    generate_subs_from_source,
    generate_srt_from_sjson, remove_subs_from_store,
    download_youtube_subs, get_transcripts_from_youtube,
    copy_or_rename_transcript,
    manage_video_subtitles_save,
    TranscriptsGenerationException,
    GetTranscriptsFromYouTubeException,
    TranscriptsRequestValidationException
)

from .access import has_course_access

__all__ = [
    'upload_transcripts',
    'download_transcripts',
    'check_transcripts',
    'choose_transcripts',
    'replace_transcripts',
    'rename_transcripts',
    'save_transcripts',
]

log = logging.getLogger(__name__)


def error_response(response, message, status_code=400):
    """
    Simplify similar actions: log message and return JsonResponse with message included in response.

    By default return 400 (Bad Request) Response.
    """
    log.debug(message)
    response['status'] = message
    return JsonResponse(response, status_code)


@login_required
def upload_transcripts(request):
    """
    Upload transcripts for current module.

    returns: response dict::

        status: 'Success' and HTTP 200 or 'Error' and HTTP 400.
        subs: Value of uploaded and saved html5 sub field in video item.
    """
    response = {
        'status': 'Unknown server error',
        'subs': '',
    }

    locator = request.POST.get('locator')
    if not locator:
        return error_response(response, 'POST data without "locator" form data.')

    try:
        item = _get_item(request, request.POST)
    except (ItemNotFoundError, InvalidLocationError, InsufficientSpecificationError):
        return error_response(response, "Can't find item by locator.")

    if 'file' not in request.FILES:
        return error_response(response, 'POST data without "file" form data.')

    video_list = request.POST.get('video_list')
    if not video_list:
        return error_response(response, 'POST data without video names.')

    try:
        video_list = json.loads(video_list)
    except ValueError:
        return error_response(response, 'Invalid video_list JSON.')

    source_subs_filedata = request.FILES['file'].read().decode('utf8')
    source_subs_filename = request.FILES['file'].name

    if '.' not in source_subs_filename:
        return error_response(response, "Undefined file extension.")

    basename = os.path.basename(source_subs_filename)
    source_subs_name = os.path.splitext(basename)[0]
    source_subs_ext = os.path.splitext(basename)[1][1:]

    if item.category != 'video':
        return error_response(response, 'Transcripts are supported only for "video" modules.')

    # Allow upload only if any video link is presented
    if video_list:
        sub_attr = source_subs_name
        try:
            # Generate and save for 1.0 speed, will create subs_sub_attr.srt.sjson subtitles file in storage.
            generate_subs_from_source({1: sub_attr}, source_subs_ext, source_subs_filedata, item)

            for video_dict in video_list:
                video_name = video_dict['video']
                # We are creating transcripts for every video source, if in future some of video sources would be deleted.
                # Updates item.sub with `video_name` on success.
                copy_or_rename_transcript(video_name, sub_attr, item, user=request.user)

            response['subs'] = item.sub
            response['status'] = 'Success'
        except Exception as ex:
            return error_response(response, ex.message)
    else:
        return error_response(response, 'Empty video sources.')

    return JsonResponse(response)


@login_required
def download_transcripts(request):
    """
    Passes to user requested transcripts file.

    Raises Http404 if unsuccessful.
    """
{'fraction_non_alphanumeric': 0.08475076197030773, 'fraction_numerical': 0.005112574968046407, 'mean_word_length': 3.6875576036866358, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4148820', 'n_tokens_mistral': 2939, 'n_tokens_neox': 2774, 'n_words': 812}