<commit_before>
package MediaWords::Controller::Api::V2::MC_REST_SimpleObject;
use Modern::Perl "2015";
use MediaWords::CommonLibs;

use strict;
use warnings;
use base 'Catalyst::Controller::REST';
use List::Util qw(first max maxstr min minstr reduce shuffle sum);
use Moose;
use namespace::autoclean;
use Readonly;

=head1 NAME

MediaWords::Controller::Media - Catalyst Controller

=head1 DESCRIPTION

Catalyst Controller.

=head1 METHODS

=cut

=head2 index

=cut

BEGIN { extends 'MediaWords::Controller::Api::V2::MC_Controller_REST' }

# Default authentication action roles
__PACKAGE__->config(    #
    action => {         #
        single => { Does => [ qw( ~PublicApiKeyAuthenticated ~Throttled ~Logged ) ] },    #
        list   => { Does => [ qw( ~PublicApiKeyAuthenticated ~Throttled ~Logged ) ] },    #
      }    #
);         #

Readonly my $ROWS_PER_PAGE => 20;

sub _purge_extra_fields
{
    my ( $self, $c, $obj ) = @_;

    my $new_obj = {};

    foreach my $default_output_field ( @{ $self->default_output_fields( $c ) } )
    {
        $new_obj->{ $default_output_field } = $obj->{ $default_output_field };
    }

    return $new_obj;
}

sub _purge_extra_fields_obj_list
{
    my ( $self, $c, $list ) = @_;

    return [ map { $self->_purge_extra_fields( $c, $_ ) } @{ $list } ];
}

sub _purge_non_permissible_fields
{
    my ( $self, $obj ) = @_;

    my $new_obj = {};
    for my $field ( @{ $self->permissible_output_fields } )
    {
        $new_obj->{ $field } = $obj->{ $field };
    }

    return $new_obj;
}

sub _purge_non_permissible_fields_obj_list
{
    my ( $self, $list ) = @_;

    return [ map { $self->_purge_non_permissible_fields( $_ ) } @{ $list } ];
}

sub default_output_fields
{
    return;
}

sub permissible_output_fields
{
    return;
}

sub has_nested_data
{
    return;
}

sub get_table_name
{
    die "Method not implemented";
}

sub has_extra_data
{
    return;
}

sub add_extra_data
{
    return;
}

sub _process_result_list
{
    my ( $self, $c, $items, $all_fields ) = @_;

    if ( $self->default_output_fields( $c ) && !$all_fields )
    {
        $items = $self->_purge_extra_fields_obj_list( $c, $items );
    }

    if ( $self->has_extra_data() )
    {
        $items = $self->add_extra_data( $c, $items );
    }

    if ( $self->has_nested_data() )
    {
        my $nested_data = int( $c->req->param( 'nested_data' ) // 1 );

        if ( $nested_data )
        {
            $items = $self->_add_nested_data( $c->dbis, $items );
        }
    }

    if ( $self->permissible_output_fields() )
    {
        $items = $self->_purge_non_permissible_fields_obj_list( $items );
    }

    return $items;
}

# action roles are to be set for each derivative sub-actions
sub single : Local : ActionClass('MC_REST')
{
}

sub single_GET
{
    my ( $self, $c, $id ) = @_;

    my $table_name = $self->get_table_name();

    # ID is typically an int, e.g. media_id or stories_id
    $id = int( $id );
    if ( $id < 1 )
    {
        die "ID must be positive.";
    }

    my $id_field = $table_name . "_id";

    my $query = "select * from $table_name where $id_field = ? ";

    my $all_fields = int( $c->req->param( 'all_fields' ) // 0 );

    my $items = $c->dbis->query( $query, $id )->hashes();

    $items = $self->_process_result_list( $c, $items, $all_fields );

    $self->status_ok( $c, entity => $items );
}

sub list_query_filter_field
{<commit_msg>fix dos vulnerability in api */single calls<commit_after>
package MediaWords::Controller::Api::V2::MC_REST_SimpleObject;
use Modern::Perl "2015";
use MediaWords::CommonLibs;

use strict;
use warnings;
use base 'Catalyst::Controller::REST';
use List::Util qw(first max maxstr min minstr reduce shuffle sum);
use Moose;
use namespace::autoclean;
use Readonly;

=head1 NAME

MediaWords::Controller::Media - Catalyst Controller

=head1 DESCRIPTION

Catalyst Controller.

=head1 METHODS

=cut

=head2 index

=cut

BEGIN { extends 'MediaWords::Controller::Api::V2::MC_Controller_REST' }

# Default authentication action roles
__PACKAGE__->config(    #
    action => {         #
        single => { Does => [ qw( ~PublicApiKeyAuthenticated ~Throttled ~Logged ) ] },    #
        list   => { Does => [ qw( ~PublicApiKeyAuthenticated ~Throttled ~Logged ) ] },    #
      }    #
);         #

Readonly my $ROWS_PER_PAGE => 20;

sub _purge_extra_fields
{
    my ( $self, $c, $obj ) = @_;

    my $new_obj = {};

    foreach my $default_output_field ( @{ $self->default_output_fields( $c ) } )
    {
        $new_obj->{ $default_output_field } = $obj->{ $default_output_field };
    }

    return $new_obj;
}

sub _purge_extra_fields_obj_list
{
    my ( $self, $c, $list ) = @_;

    return [ map { $self->_purge_extra_fields( $c, $_ ) } @{ $list } ];
}

sub _purge_non_permissible_fields
{
    my ( $self, $obj ) = @_;

    my $new_obj = {};
    for my $field ( @{ $self->permissible_output_fields } )
    {
        $new_obj->{ $field } = $obj->{ $field };
    }

    return $new_obj;
}

sub _purge_non_permissible_fields_obj_list
{
    my ( $self, $list ) = @_;

    return [ map { $self->_purge_non_permissible_fields( $_ ) } @{ $list } ];
}

sub default_output_fields
{
    return;
}

sub permissible_output_fields
{
    return;
}

sub has_nested_data
{
    return;
}

sub get_table_name
{
    die "Method not implemented";
}

sub has_extra_data
{
    return;
}

sub add_extra_data
{
    return;
}

sub _process_result_list
{
    my ( $self, $c, $items, $all_fields ) = @_;

    if ( $self->default_output_fields( $c ) && !$all_fields )
    {
        $items = $self->_purge_extra_fields_obj_list( $c, $items );
    }

    if ( $self->has_extra_data() )
    {
        $items = $self->add_extra_data( $c, $items );
    }

    if ( $self->has_nested_data() )
    {
        my $nested_data = int( $c->req->param( 'nested_data' ) // 1 );

        if ( $nested_data )
        {
            $items = $self->_add_nested_data( $c->dbis, $items );
        }
    }

    if ( $self->permissible_output_fields() )
    {
        $items = $self->_purge_non_permissible_fields_obj_list( $items );
    }

    return $items;
}

# action roles are to be set for each derivative sub-actions
sub single : Local : ActionClass('MC_REST')
{
}

sub single_GET
{
    my ( $self, $c, $id ) = @_;

    my $table_name = $self->get_table_name();

    # ID is typically an int, e.g. media_id or stories_id
    $id = int( $id );
    if ( $id < 1 )
    {
        die "ID must be positive.";
    }

    # really big numbers eventually get treated as the numeric type in postgres, which triggers a seq scan
    if ( $id > 2**64 )
    {
        die "ID cannot be greater than 64 bits";
    }

    my $id_field = $table_name . "_id";

    my $query = "select * from $table_name where $id_field = ? ";

    my $all_fields = int( $c->req->param( 'all_fields' ) // 0 );

    my $items = $c->dbis->query( $query, $id )->hashes();

    $items = $self->_process_result_list( $c, $items, $all_fields );

    $self->status_ok( $c, entity => $items );
}

sub list_query_filter_field
{
{'fraction_non_alphanumeric': 0.15018471156578572, 'fraction_numerical': 0.004973003694231316, 'mean_word_length': 2.8654585392641407, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 74, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5328180', 'n_tokens_mistral': 2663, 'n_tokens_neox': 2550, 'n_words': 569}