Group
Extension

WebService-Mattermost/lib/WebService/Mattermost/V4/API/Resource.pm

package WebService::Mattermost::V4::API::Resource;

# ABSTRACT: Base class for API resources.

use List::MoreUtils 'all';
use Moo;
use Types::Standard qw(Bool HashRef Maybe Object Str);

use WebService::Mattermost::Helper::Alias 'view';
use WebService::Mattermost::V4::API::Object::Channel;
use WebService::Mattermost::V4::API::Object::Icon;
use WebService::Mattermost::V4::API::Object::Status;
use WebService::Mattermost::V4::API::Object::Team;
use WebService::Mattermost::V4::API::Object::TeamMember;
use WebService::Mattermost::V4::API::Object::TeamStats;
use WebService::Mattermost::V4::API::Object::Plugins;
use WebService::Mattermost::V4::API::Object::Results;
use WebService::Mattermost::V4::API::Object::User;
use WebService::Mattermost::V4::API::Request;
use WebService::Mattermost::V4::API::Response;

with qw(
    WebService::Mattermost::Role::Logger
    WebService::Mattermost::Role::Returns
    WebService::Mattermost::Role::UserAgent
    WebService::Mattermost::V4::API::Role::RequireID
    WebService::Mattermost::V4::API::Role::NewRelatedResource
);

################################################################################

has api        => (is => 'ro', isa => Object, required => 1);
has base_url   => (is => 'ro', isa => Str,    required => 1);
has resource   => (is => 'ro', isa => Str,    required => 1);
has auth_token => (is => 'rw', isa => Str,    required => 1);

has DELETE  => (is => 'ro', isa => Str,     default => 'DELETE');
has GET     => (is => 'ro', isa => Str,     default => 'GET');
has headers => (is => 'ro', isa => HashRef, default => sub { {} });
has POST    => (is => 'ro', isa => Str,     default => 'POST');
has PUT     => (is => 'ro', isa => Str,     default => 'PUT');
has debug   => (is => 'ro', isa => Bool,    default => 0);

has id => (is => 'rw', isa => Maybe[Str]);

################################################################################

sub _delete {
    my $self = shift;
    my $args = shift;

    $args->{method} = $self->DELETE;

    return $self->_call($args);
}

sub _single_view_delete {
    my $self = shift;
    my $args = shift;

    $args->{single} = 1;

    return $self->_delete($args);
}

sub _get {
    my $self = shift;
    my $args = shift;

    $args->{method} = $self->GET;

    return $self->_call($args);
}

sub _single_view_get {
    my $self = shift;
    my $args = shift;

    $args->{single} = 1;

    return $self->_get($args);
}

sub _post {
    my $self = shift;
    my $args = shift;

    $args->{method} = $self->POST;

    return $self->_call($args);
}

sub _single_view_post {
    my $self = shift;
    my $args = shift;

    $args->{single} = 1;

    return $self->_post($args);
}

sub _put {
    my $self = shift;
    my $args = shift;

    $args->{method} = $self->PUT;

    return $self->_call($args);
}

sub _single_view_put {
    my $self = shift;
    my $args = shift;

    $args->{method} = $self->PUT;

    return $self->_put($args);
}

sub _call {
    my $self = shift;
    my $args = shift;

    if ($args->{required}) {
        my $validation = $self->_validate($args->{parameters}, $args->{required});

        return $validation unless $validation->{valid};
    }

    my %headers = ('Keep-Alive' => 1);

    if ($self->auth_token) {
        $headers{Authorization} = $self->bearer($self->auth_token);
    }

    my $request = $self->_as_request($args);
    my $method  = lc $request->method;

    my $form_type;

    if (grep { $_ eq $request->method } ($self->PUT, $self->POST)) {
        $form_type = 'json';
    } else {
        $form_type = 'form';
    }

    $form_type = $args->{override_data_type} if $args->{override_data_type};

    my $tx = $self->ua->$method(
        $request->url => \%headers,
        $form_type    => $request->parameters,
    );

    if (my $error = $tx->req->error) {
        $self->logger->warn('No HTTP code was received from Mattermost. Is your server alive?');
        $self->logger->warnf('The following may be useful: %s', $error->{message});
    }

    return $self->_as_response($tx->res, $args);
}

sub _as_request {
    my $self = shift;
    my $args = shift;

    $args->{auth_token} = $self->auth_token;
    $args->{base_url}   = $self->base_url;
    $args->{resource}   = $self->resource;
    $args->{debug}      = $self->debug;

    $args->{endpoint}   ||= '';
    $args->{parameters} ||= {};

    return WebService::Mattermost::V4::API::Request->new($args);
}

sub _as_response {
    my $self = shift;
    my $res  = shift;
    my $args = shift;

    my $view_name = $self->can('view_name') && $self->view_name;

    if ($args->{view}) {
        $view_name = $args->{view};
    }

    if ($res->is_error && $self->debug) {
        $self->logger->warnf('An API error occurred: %s', $res->message);
    }

    return WebService::Mattermost::V4::API::Response->new({
        auth_token  => $self->auth_token,
        base_url    => $self->base_url,
        code        => $res->code || 0,
        headers     => $res->headers,
        is_error    => $res->is_error   ? 1 : 0,
        is_success  => $res->is_success ? 1 : 0,
        message     => $res->message,
        prev        => $res,
        raw_content => $res->body,
        item_view   => $view_name,
        single_item => $args->{single},
    });
}

sub _validate {
    my $self     = shift;
    my $args     = shift;
    my $required = shift;

    my %slice;

    # Grab a slice of the keys from given arguments
    @slice{@{$required}} = @{$args}{@{$required}};

    # Return early, all's well
    return { valid => 1 } if all { defined($_) } values %slice;

    my @missing;

    foreach my $kx (@{$required}) {
        push @missing, $kx unless $args->{$kx};
    }

    return {
        valid   => 0,
        missing => \@missing,
        error   => sprintf('Required parameters missing: %s', join(', ', @missing)),
    };
}

################################################################################

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

WebService::Mattermost::V4::API::Resource - Base class for API resources.

=head1 VERSION

version 0.31

=head1 DESCRIPTION

=head2 ATTRIBUTES

=over 4

=item C<auth_token>

An auth token to use in the headers for every API call. Authentication is
required to use the Mattermost API.

=item C<base_url>

The API's base URL.

=item C<resource>

The name of the API resource, for example L<WebService::Mattermost::V4::API::Brand>'s
resource is 'brand'.

=back

=head1 AUTHOR

Mike Jones <mike@netsplit.org.uk>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2023 by Mike Jones.

This is free software, licensed under:

  The MIT (X11) License

=cut


Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.