CallBackery

 view release on metacpan or  search on metacpan

lib/CallBackery/Model/ConfigJsonSchema.pm  view on Meta::CPAN

    my $validator = JSON::Validator->new();
    $validator->schema($self->schema);
    return $validator;
}


=head2 postProcessCfg

Post process the configuration data into a format that is easily used
by the application.

=cut

sub postProcessCfg ($self) {
    my $cfg = $self->cfgHash;
    my $schema = $self->schema;
    my @items;
    my %pluginMap;
    my @fullPluginList;
    my @pluginList;
    for my $prop (keys %{$schema->{properties}{BACKEND}{properties}}) {
        my $default = $schema->{properties}{BACKEND}{properties}{$prop}{default};
        $cfg->{BACKEND}{$prop} //= $default if $default;
    }
    for my $prop (keys %{$schema->{properties}{FRONTEND}{properties}}) {
        my $default = $schema->{properties}{FRONTEND}{properties}{$prop}{default};
        $cfg->{FRONTEND}{$prop} //= $default if $default;
    }
    for my $item (@{$cfg->{PLUGIN}}) {
        my ($name) = keys %$item;
        push @fullPluginList, $name;
        push @pluginList, $name
            if not $item->{$name}{unlisted};
        Mojo::Exception->throw("Duplicated plugin instance $name")
          if exists $pluginMap{$name};
        my $obj = eval { 
            $self->loadAndNewPlugin($item->{$name}{module});
        };
        if ($@){
            warn "Failed to load Plugin $name: $@";
            next;
        }
        $obj->config($item->{$name});
        $obj->name($name);
        $obj->app($self->app);
        $pluginMap{$name} = $obj;
        push @items, {
            type => 'object',
            properties => {
                $name => $obj->schema,
            },
            required => [ $name ],
            additionalProperties => false,
        };
    }

    $schema->{properties}{PLUGIN}{items} = {
        anyOf => \@items
    };

    $schema->{properties}{FRONTEND}{properties}{$_.'_popup'}
        {properties}{plugin}{enum} = \@fullPluginList 
            for qw(registration passwordreset);

    # warn YAML::XS::Dump $schema;
    # second pass with data structures from plugins integrated
    if (my @errors = $self->validator->validate($cfg)){
        Mojo::Exception->throw(join "\n",@errors);
    }

    $cfg->{PLUGIN} = {
        prototype => \%pluginMap,
        list => \@pluginList
    };

    for (qw(registration passwordreset)) {
        if (my $popup = $cfg->{FRONTEND}{$_.'_popup'}){
            my $plugin = delete $popup->{plugin};
            my $obj = $pluginMap{$plugin};
            $cfg->{FRONTEND}{$_.'_popup'} = {
                popupTitle => $obj->config->{'tab-name'},
                name => $plugin,
                %$popup,
            };
        }
    }
    #warn YAML::XS::Dump($cfg->{FRONTEND})
    for my $name (@fullPluginList) {
        $pluginMap{$name}->massageConfig($cfg);
    }

    $cfg->{FRONTEND}{TRANSLATIONS} = $self->getTranslations();
    return $cfg;
}

1;

__DATA__

@@ config-schema.yaml

$id: https://callbackery.org/config-schema.yaml
$schema: http://json-schema.org/draft2019/schema#
definitions:
  plugin:
    type: object
    additionalProperties: false
    required:
      - plugin
    properties:
      plugin:
        type: string
      set:
        type: object

type: object
additionalProperties: false
required:
  - BACKEND
  - FRONTEND
  - PLUGIN
properties:
  BACKEND:
    type: object
    additionalProperties: false
    required:
      - cfg_db
    properties:
      log_file:
        type: string
      cfg_db:
        type: string
      sesame_user:
        type: string
      sesame_pass:
        type: string
  FRONTEND:
    type: object
    additionalProperties: false
    properties:
      logo:
        type: string
        format: uri
        description: url for the logo brand the login screen
      company_name:
        type: string
        description: who created the app
      company_url:
        type: string
        format: uri
        description: link to the company homepage
      max_width:
        type: integer
        description: maximum content width
      company_support:
        type: string
        format: uri
        description: company support eMail
      logo_small:
        description: for the small logo brand the UI
        type: string
        format: uri
      logo_noscale:
        type: boolean
        description: don't scale the login window logo
        default: false
      spinner:
        type: string
        format: uri
        description: url for the busy animation spinner gif
      title:
        type: string
        description: title string for the application
      initial_plugin:
        type: string
        description: which tab should be active upon login ?
      hide_password:
        type: boolean
        description: hide password field on login screen
      hide_password_icon:
        type: boolean
        description: hide password dialog icon
        default: false
      hide_release:
        type: boolean
        description: hide release string on login screen
        default: false
      hide_company:
        type: boolean
        description: hide company string on login screen
        default: false
      registration_popup:
        $ref: "#/definitions/plugin"
      passwordreset_popup:
        $ref: "#/definitions/plugin"

  PLUGIN:
    type: array
    items:
        type: object
        maxProperties: 1
        minProperties: 1
        patternProperty:
            ^\S+$:
                type: object
                required:
                - module
                properties:
                module:
                    type: string
                unlisted:
                    description: do not add this plugin to the plugin list.
                    type: boolean




__END__

=head1 COPYRIGHT

Copyright (c) 2020 by OETIKER+PARTNER AG. All rights reserved.

=head1 AUTHOR

S<Tobias Oetiker E<lt>tobi@oetiker.chE<gt>>

=head1 HISTORY

 2020-02-18 to 1.0 first version
 2020-11-20 fz 1.1 call postProcessCfg from CallBackery.pm

=cut

# Emacs Configuration
#
# Local Variables:
# mode: cperl
# eval: (cperl-set-style "PerlStyle")
# mode: flyspell
# mode: flyspell-prog
# End:
#
# vi: sw=4 et



( run in 1.045 second using v1.01-cache-2.11-cpan-364913b4093 )