Initial commit.

This commit is contained in:
Sergiotarxz 2023-08-02 16:19:44 +02:00
parent 46ae5930bc
commit fe3dc21b56
27 changed files with 1335 additions and 0 deletions

37
.eslintrc.js Normal file
View File

@ -0,0 +1,37 @@
module.exports = {
env: {
browser: true,
es2021: true
},
extends: [
'plugin:react/recommended',
'standard-with-typescript'
],
overrides: [
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: 'tsconfig.json'
},
plugins: [
'react',
'no-relative-import-paths'
],
rules: {
indent: ['error', 4, { SwitchCase: 1 }],
'no-relative-import-paths/no-relative-import-paths': ['warn', { allowSameFolder: true }],
'@typescript-eslint/indent': ['error', 4],
'react/jsx-indent': ['error', 4],
'react/jsx-indent-props': ['error', 4]
},
settings: {
'import/resolver': {
typescript: {
project: [
'tsconfig.json'
]
}
}
}
}

34
Build.PL Normal file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env perl
use Module::Build;
my $home = $ENV{HOME};
my $build = Module::Build->new(
module_name => 'OwlcodeAds',
license => 'AGPLv3',
dist_author => 'Sergio Iglesias <contact@owlcode.tech>',
dist_abstract => 'Web de anuncios de Owlcode.tech.',
requires => {
'Email::MIME' => 0,
'Email::Sender::Simple' => 0,
'Email::Sender::Transport::SMTP' => 0,
'Mojolicious' => 0,
'Moo' => 0,
'Crypt::URandom' => 0,
'Crypt::Bcrypt' => 0,
'JSON' => 0,
'DBIx::Class' => 0,
'DBD::Pg' => 0,
'DBIx::Class::DeploymentHandler' => 0,
'UUID::URandom' => 0,
'Module::Pluggable' => 0,
'Mojo::Redis' => 0,
'List::AllUtils' => 0,
'DateTime::Format::Pg' => 0,
'DateTime::Format::ISO8601::Format' => 0,
'Test::Most' => 0,
'Carp::Always' => 0,
'Try::Tiny' => 0,
},
);
$build->create_build_script;

5
babel.config.json Normal file
View File

@ -0,0 +1,5 @@
{
"presets": [
"@babel/preset-react"
]
}

View File

@ -0,0 +1,18 @@
--
-- Created by SQL::Translator::Producer::PostgreSQL
-- Created on Wed Aug 2 16:12:43 2023
--
;
--
-- Table: dbix_class_deploymenthandler_versions
--
CREATE TABLE "dbix_class_deploymenthandler_versions" (
"id" serial NOT NULL,
"version" character varying(50) NOT NULL,
"ddl" text,
"upgrade_sql" text,
PRIMARY KEY ("id"),
CONSTRAINT "dbix_class_deploymenthandler_versions_version" UNIQUE ("version")
);
;

View File

@ -0,0 +1,25 @@
--
-- Created by SQL::Translator::Producer::PostgreSQL
-- Created on Wed Aug 2 16:12:43 2023
--
;
--
-- Table: users
--
CREATE TABLE "users" (
"uuid" uuid NOT NULL,
"username" text NOT NULL,
"name" text NOT NULL,
"surname" text NOT NULL,
"encrypted_password" text NOT NULL,
"email" text NOT NULL,
"verified" boolean NOT NULL,
"verification_token" text,
"register_date" timestamp DEFAULT NOW() NOT NULL,
"last_activity" timestamp DEFAULT NOW() NOT NULL,
PRIMARY KEY ("uuid"),
CONSTRAINT "unique_constraint_email" UNIQUE ("email"),
CONSTRAINT "unique_constraint_username" UNIQUE ("username")
);
;

View File

@ -0,0 +1,26 @@
-- Convert schema '/home/sergio/OwlcodeAds/script/../dbicdh/_source/deploy/-1/001-auto.yml' to '/home/sergio/OwlcodeAds/script/../dbicdh/_source/deploy/0/001-auto.yml':;
;
BEGIN;
;
CREATE TABLE "users" (
"uuid" uuid NOT NULL,
"username" text NOT NULL,
"name" text NOT NULL,
"surname" text NOT NULL,
"encrypted_password" text NOT NULL,
"email" text NOT NULL,
"verified" boolean NOT NULL,
"verification_token" text,
"register_date" timestamp DEFAULT NOW() NOT NULL,
"last_activity" timestamp DEFAULT NOW() NOT NULL,
PRIMARY KEY ("uuid"),
CONSTRAINT "unique_constraint_email" UNIQUE ("email"),
CONSTRAINT "unique_constraint_username" UNIQUE ("username")
);
;
COMMIT;

View File

@ -0,0 +1,91 @@
---
schema:
procedures: {}
tables:
dbix_class_deploymenthandler_versions:
constraints:
- deferrable: 1
expression: ''
fields:
- id
match_type: ''
name: ''
on_delete: ''
on_update: ''
options: []
reference_fields: []
reference_table: ''
type: PRIMARY KEY
- deferrable: 1
expression: ''
fields:
- version
match_type: ''
name: dbix_class_deploymenthandler_versions_version
on_delete: ''
on_update: ''
options: []
reference_fields: []
reference_table: ''
type: UNIQUE
fields:
ddl:
data_type: text
default_value: ~
is_nullable: 1
is_primary_key: 0
is_unique: 0
name: ddl
order: 3
size:
- 0
id:
data_type: int
default_value: ~
is_auto_increment: 1
is_nullable: 0
is_primary_key: 1
is_unique: 0
name: id
order: 1
size:
- 0
upgrade_sql:
data_type: text
default_value: ~
is_nullable: 1
is_primary_key: 0
is_unique: 0
name: upgrade_sql
order: 4
size:
- 0
version:
data_type: varchar
default_value: ~
is_nullable: 0
is_primary_key: 0
is_unique: 1
name: version
order: 2
size:
- 50
indices: []
name: dbix_class_deploymenthandler_versions
options: []
order: 1
triggers: {}
views: {}
translator:
add_drop_table: 0
filename: ~
no_comments: 0
parser_args:
sources:
- __VERSION
parser_type: SQL::Translator::Parser::DBIx::Class
producer_args: {}
producer_type: SQL::Translator::Producer::YAML
show_warnings: 0
trace: 0
version: 1.63

View File

@ -0,0 +1,164 @@
---
schema:
procedures: {}
tables:
users:
constraints:
- deferrable: 1
expression: ''
fields:
- uuid
match_type: ''
name: ''
on_delete: ''
on_update: ''
options: []
reference_fields: []
reference_table: ''
type: PRIMARY KEY
- deferrable: 1
expression: ''
fields:
- email
match_type: ''
name: unique_constraint_email
on_delete: ''
on_update: ''
options: []
reference_fields: []
reference_table: ''
type: UNIQUE
- deferrable: 1
expression: ''
fields:
- username
match_type: ''
name: unique_constraint_username
on_delete: ''
on_update: ''
options: []
reference_fields: []
reference_table: ''
type: UNIQUE
fields:
email:
data_type: text
default_value: ~
is_nullable: 0
is_primary_key: 0
is_unique: 1
name: email
order: 6
size:
- 0
encrypted_password:
data_type: text
default_value: ~
is_nullable: 0
is_primary_key: 0
is_unique: 0
name: encrypted_password
order: 5
size:
- 0
last_activity:
data_type: timestamp
default_value: !!perl/ref
=: NOW()
is_nullable: 0
is_primary_key: 0
is_unique: 0
name: last_activity
order: 10
size:
- 0
name:
data_type: text
default_value: ~
is_nullable: 0
is_primary_key: 0
is_unique: 0
name: name
order: 3
size:
- 0
register_date:
data_type: timestamp
default_value: !!perl/ref
=: NOW()
is_nullable: 0
is_primary_key: 0
is_unique: 0
name: register_date
order: 9
size:
- 0
surname:
data_type: text
default_value: ~
is_nullable: 0
is_primary_key: 0
is_unique: 0
name: surname
order: 4
size:
- 0
username:
data_type: text
default_value: ~
is_nullable: 0
is_primary_key: 0
is_unique: 1
name: username
order: 2
size:
- 0
uuid:
data_type: uuid
default_value: ~
is_nullable: 0
is_primary_key: 1
is_unique: 0
name: uuid
order: 1
size:
- 0
verification_token:
data_type: text
default_value: ~
is_nullable: 1
is_primary_key: 0
is_unique: 0
name: verification_token
order: 8
size:
- 0
verified:
data_type: boolean
default_value: ~
is_nullable: 0
is_primary_key: 0
is_unique: 0
name: verified
order: 7
size:
- 0
indices: []
name: users
options: []
order: 1
triggers: {}
views: {}
translator:
add_drop_table: 0
filename: ~
no_comments: 0
parser_args:
sources:
- User
parser_type: SQL::Translator::Parser::DBIx::Class
producer_args: {}
producer_type: SQL::Translator::Producer::YAML
show_warnings: 0
trace: 0
version: 1.63

View File

@ -0,0 +1,16 @@
import * as React from 'react'
import * as ReactRouter from 'react-router-dom'
const router = ReactRouter.createBrowserRouter([
{
path: '/',
element: (<div>hello</div>)
}
])
export default function Page (): JSX.Element {
return (
<React.StrictMode>
<ReactRouter.RouterProvider router={router}/>
</React.StrictMode>
)
}

16
js-src/index.tsx Normal file
View File

@ -0,0 +1,16 @@
'use strict'
import * as React from 'react'
import * as ReactDOMClient from 'react-dom/client'
import Page from '@owlads/components/page'
import '@owlads/style.scss'
window.addEventListener('load', () => {
const container = document.querySelector('div.app-container')
console.log(container)
if (container !== null) {
const root = ReactDOMClient.createRoot(container)
console.log('hola')
root.render(<Page/>)
}
})

48
lib/OwlcodeAds.pm Normal file
View File

@ -0,0 +1,48 @@
package OwlcodeAds;
use v5.36.0;
use strict;
use warnings;
use utf8;
use Mojo::Base 'Mojolicious', -signatures;
# This method will run once at server start
sub startup ($self) {
my $sessions = Mojolicious::Sessions->new;
$sessions->cookie_name('OwlcodeAds');
$sessions->default_expiration(0);
$self->sessions($sessions);
# Load configuration from config file
my $config = $self->plugin('NotYAMLConfig');
# Configure the application
$self->secrets( $config->{secrets} );
# Router
my $r = $self->routes;
# Normal route to controller
{
my $api = $r->any('/api');
{
my $user = $api->any('/user');
$user->post('/')->to('Register#register');
}
$api->any(
'/*' => sub ($c) {
$c->render(
status => 404,
json => {
error => 'Enpoint not found.'
}
);
}
);
}
$r->get('/*')->to('React#react');
$r->get('/')->to('React#react');
}
1;

View File

@ -0,0 +1,16 @@
package OwlcodeAds::Controller::React;
use v5.36.0;
use strict;
use warnings;
use utf8;
use Mojo::Base 'Mojolicious::Controller', -signatures;
use UUID::URandom qw/create_uuid_string/;
sub react ($self) {
$self->render;
}
1;

View File

@ -0,0 +1,185 @@
package OwlcodeAds::Controller::Register;
use v5.36.0;
use strict;
use warnings;
use utf8;
use Mojo::Base 'Mojolicious::Controller', -signatures;
use UUID::URandom qw/create_uuid_string/;
sub register ($self) {
my $params;
eval { $params = $self->req->json; };
if ($@) {
return $self->render(
status => 400,
json => {
error => 'The input is not a json.',
}
);
}
if ( ref $params ne 'HASH' ) {
return $self->render(
status => 400,
json => {
error => 'The input MUST be a json object.',
}
);
}
my ( $uuid, $username, $name, $surname, $password, $repeat_password, $email, $verified );
eval {
(
$uuid, $username, $name, $surname, $password, $repeat_password,
$email, $verified
) = $self->_validate_or_die($params);
};
if ($@) {
if ( $self->config->{debug} > 1 ) {
# It is pretty probable that this user error is very common and
# not always will be needed when enabling debug
# to see this errors, so we use the second level
# of verbosity.
say STDERR $@;
}
return;
}
$self->_register( $uuid, $username, $name, $surname, $password, $email,
$verified );
}
sub _validate_or_die ( $self, $params ) {
require OwlcodeAds::Email;
my $mailer = OwlcodeAds::Email->new;
my $uuid = create_uuid_string();
my $username = $self->_force_non_empty( $params, 'username' );
my $name = $self->_force_non_empty( $params, 'name' );
my $surname = $self->_force_non_empty( $params, 'surname' );
my $password = $self->_force_valid_password( $params, 'password' );
my $repeat_password =
$self->_force_valid_password( $params, 'repeat_password' );
my $email = $self->_force_valid_email( $params, 'email' );
my $verified = $mailer->disabled ? 1 : 0;
return ( $uuid, $username, $name, $surname, $password, $repeat_password,
$email, $verified );
}
sub _register (
$self, $uuid, $username,
$name, $surname, $password,
$repeat_password, $email, $verified
)
{
require OwlcodeAds::Schema;
require OwlcodeAds::Email;
my $schema = OwlcodeAds::Schema->new;
my $mailer = OwlcodeAds::Email->new;
my $resultset = $schema->resultset('User');
my $user = $resultset->new(
{
uuid => $uuid,
username => $username,
name => $name,
surname => $surname,
password => $password,
email => $email,
verified => $verified,
}
);
eval { $user->insert; };
if ($@) {
print STDERR $@;
$self->render(
status => 500,
json => {
error => 'Unable to create user (Server Error).'
}
);
return;
}
$self->render(
status => 200,
json => $user->serialize,
);
}
sub _force_valid_email ( $self, $params, $key ) {
my $email = $self->_force_non_empty( $params, $key );
my ( $username, $domain ) = $email =~ /^(.*?)@(.*)$/;
if ( !defined $username || length $username == 0 ) {
$self->render(
status => 400,
json => {
error => "$key has not the username part of the domain name.",
}
);
die;
}
if ( !defined $domain || $domain !~ /\w\.\w/ ) {
$self->render(
status => 400,
json => {
error => "$key has not a valid hostname after @.",
}
);
die;
}
if ( $domain =~ /@/ ) {
$self->render(
status => 400,
json => {
error =>
"Found multiple @ in the email, refusing to take this mail."
}
);
}
return $email;
}
sub _force_valid_password ( $self, $params, $key ) {
my $password = $self->_force_non_empty( $params, $key );
if ( length $password < 8 ) {
$self->render(
status => 400,
json => {
error => "$key should have at least 8 characters.",
}
);
die;
}
return $password;
}
sub _force_non_empty ( $self, $hash, $key ) {
my $value = $self->_force_defined( $hash->{$key} );
if ( length $value == 0 ) {
$self->render(
status => 400,
json => {
error => "$key must be non empty in json input.",
},
);
die;
}
return $value;
}
sub _force_defined ( $self, $hash, $key ) {
my $value = $hash->{$key};
if ( !defined $value ) {
$self->render(
status => 400,
json => {
error => "$key must be defined in json input.",
}
);
die;
}
return $value;
}
1;

161
lib/OwlcodeAds/Email.pm Normal file
View File

@ -0,0 +1,161 @@
package OwlcodeAds::Email;
use v5.36.0;
use strict;
use warnings;
use utf8;
use feature 'signatures';
use Encode qw/decode/;
use Moo;
use Email::Sender::Transport::SMTP;
use Email::Sender::Simple;
use Email::MIME;
has app => ( is => 'lazy', );
has username => ( is => 'lazy', );
has host => ( is => 'lazy', );
has password => ( is => 'lazy' );
has config => ( is => 'lazy' );
has from => ( is => 'lazy' );
has disabled => ( is => 'lazy' );
sub _build_disabled ($self) {
my $config = $self->config;
return $config->{disabled} // 0;
}
sub _build_app ($self) {
require OwlcodeAds;
return OwlcodeAds->new;
}
sub _build_config ($self) {
my $app = $self->app;
my $config = $app->config->{email};
if ( !defined $config || ref $config ne 'HASH' ) {
die 'email key not found in global config, cannot send email.';
}
return $config;
}
sub _build_username ($self) {
my $config = $self->config;
my $username = $config->{username};
if ( !defined $username ) {
die
'email key does not have a username key in global config, cannot send email';
}
return $username;
}
sub _build_password ($self) {
my $config = $self->config;
my $password = $config->{password};
if ( !defined $password ) {
die
'email key does not have a password key in global config, cannot send email';
}
return $password;
}
sub _build_host ($self) {
my $config = $self->config;
my $host = $config->{host};
if ( !defined $host ) {
die
'email key does not have a host key in global config, cannot send email';
}
return $host;
}
sub _build_from ($self) {
my $config = $self->config;
my $from = $config->{from};
if ( !defined $from ) {
die
'email key does not have a from key in global config, cannot send email';
}
return $from;
}
sub _generate_transport {
my $self = shift;
my $username = $self->username;
my $password = $self->password;
my $host = $self->host;
my $port = $self->port;
my $transport = Email::Sender::Transport::SMTP->new(
hosts => [$host],
ssl => 1,
port => $port,
sasl_username => $username,
sasl_password => $password,
);
return $transport;
}
sub email ( $self, $text, $to, $subject = 'Email sin título', $html = undef ) {
my $username = $self->username;
my @parts = (
Email::MIME->create(
attributes => {
content_type => 'multipart/alternative',
encoding => 'base64',
},
parts => [
Email::MIME->create(
attributes => {
charset => 'UTF-8',
content_type => 'text/plain',
encoding => 'base64',
disposition => 'inline',
},
body_str => decode( 'utf-8', $text ),
),
(
( defined $html )
? (
Email::MIME->create(
attributes => {
charset => 'UTF-8',
content_type => 'text/html',
encoding => 'base64',
disposition => 'inline',
},
body_str => decode( 'utf-8', $html ),
)
)
: ()
)
]
)
);
my $username = $self->username;
my $config = $self->_config;
my $email = Email::MIME->create(
header_str => [
From => decode('utf-8', $username),
To => $to,
Subject => decode('utf-8', $subject),
],
attributes => {
encoding => 'base64',
content_type => 'multipart/mixed'
},
parts => [@parts],
);
say Email::Sender::Simple->send( $email,
{ transport => $self->_generate_transport } );
}
1;

60
lib/OwlcodeAds/Schema.pm Normal file
View File

@ -0,0 +1,60 @@
package OwlcodeAds::Schema;
use v5.36.0;
use strict;
use warnings;
our $VERSION = 0;
use feature 'signatures';
use parent 'DBIx::Class::Schema';
__PACKAGE__->load_namespaces();
my $schema;
sub Schema ($class) {
if ( !defined $schema ) {
require OwlcodeAds;
my $app = OwlcodeAds->new;
my $config = $app->{config};
my $database_config = $config->{database};
my $dbname = $database_config->{dbname};
my $host = $database_config->{host};
my $port = $database_config->{port};
my $user = $database_config->{user};
my $password = $database_config->{password};
my $dsn = 'dbi:Pg:';
if ( !defined $dbname ) {
die "The key database/dbname must be configured.";
}
$dsn .= "dbname=$dbname";
if ( defined $host ) {
$dsn .= ";host=$host";
}
if ( defined $port ) {
$dsn .= ";port=$port";
}
# Undef is perfectly fine for username and password.
$schema = $class->connect(
$dsn, $user,
$password,
{
auto_savepoint => 1,
Callbacks => {
connected => sub {
shift->do('set timezone = UTC');
return;
}
}
}
);
}
return $schema;
}
1;

View File

@ -0,0 +1,73 @@
package OwlcodeAds::Schema::Result::User;
use v5.36.0;
use strict;
use warnings;
use parent 'DBIx::Class::Core';
__PACKAGE__->table('users');
__PACKAGE__->add_columns(
uuid => {
data_type => 'uuid',
is_nullable => 0,
},
username => {
data_type => 'text',
is_nullable => 0,
},
name => {
data_type => 'text',
is_nullable => 0,
},
surname => {
data_type => 'text',
is_nullable => 0,
},
encrypted_password => {
data_type => 'text',
is_nullable => 0,
},
email => {
data_type => 'text',
is_nullable => 0,
},
verified => {
data_type => 'boolean',
is_nullable => 0,
},
verification_token => {
data_type => 'text',
is_nullable => 1,
},
register_date => {
data_type => 'timestamp',
is_nullable => 0,
default_value => \'NOW()',
},
last_activity => {
data_type => 'timestamp',
is_nullable => 0,
default_value => \'NOW()',
},
);
sub serialize ($self) {
return {
uuid => $self->uuid,
username => $self->username,
name => $self->name,
surname => $self->surname,
email => $self->email,
verified => $self->verified,
register_date => $self->register_date,
last_activity => $self->last_activity,
};
}
__PACKAGE__->set_primary_key('uuid');
__PACKAGE__->add_unique_constraint( "unique_constraint_username",
['username'] );
__PACKAGE__->add_unique_constraint( "unique_constraint_email", ["email"] );
1;

19
owlcode_ads.example.yml Normal file
View File

@ -0,0 +1,19 @@
---
secrets:
- change_me_for_a_proper_secret_generated_with_pwgen
database:
dbname: owlcode_ads
host: localhost
port: 5432
user: lastres
password: topsecret
hypnotoad:
listen:
- http://*:3000
email:
disabled: 0
host: example.com
username: example@example.com
password: topsecret
from: I am a example, change me <example@example.com>
debug: 0

49
package.json Normal file
View File

@ -0,0 +1,49 @@
{
"name": "OwlcodeAds",
"version": "0.1.1",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"@babel/preset-react": "^7.18.6",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@typescript-eslint/eslint-plugin": "^5.57.0",
"babel-loader": "^9.1.2",
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^5.0.1",
"eslint": "^8.36.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-import-resolver-typescript": "^3.5.3",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.6.1",
"eslint-plugin-no-relative-import-paths": "^1.5.2",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.32.2",
"file-loader": "^6.2.0",
"mini-css-extract-plugin": "^2.7.6",
"sass": "^1.64.2",
"sass-loader": "^13.3.2",
"style-loader": "^3.3.3",
"ts-loader": "^9.4.2",
"typescript": "^5.0.2",
"typescript-transform-paths": "^3.4.6",
"url-loader": "^4.1.1",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.2"
},
"dependencies": {
"@reduxjs/toolkit": "^1.9.5",
"babel-preset-react": "^6.24.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.1.2",
"react-router": "^6.14.2",
"react-router-dom": "^6.14.2"
}
}

3
public/js/main.bundle.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,62 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @remix-run/router v1.7.2
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
/**
* React Router DOM v6.14.2
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
/**
* React Router v6.14.2
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/

30
script/install.pl Normal file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env perl
use strict;
use warnings;
use aliased 'DBIx::Class::DeploymentHandler' => 'DH';
use Getopt::Long;
use FindBin;
use lib "$FindBin::Bin/../lib";
use OwlcodeAds::Schema;
my $force_overwrite = 0;
unless ( GetOptions( 'force_overwrite!' => \$force_overwrite ) ) {
die "Invalid options";
}
my $schema = OwlcodeAds::Schema->Schema;
my $dh = DH->new(
{
schema => $schema,
script_directory => "$FindBin::Bin/../dbicdh",
databases => 'PostgreSQL',
sql_translator_args => { add_drop_table => 0 },
force_overwrite => $force_overwrite,
}
);
$dh->install({version => 0});
$dh->upgrade;

11
script/owlcode_ads Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Mojo::File qw(curfile);
use lib curfile->dirname->sibling('lib')->to_string;
use Mojolicious::Commands;
# Start command line interface for application
Mojolicious::Commands->start_app('OwlcodeAds');

47
script/prepare.pl Normal file
View File

@ -0,0 +1,47 @@
#!/usr/bin/env perl
use strict;
use warnings;
use aliased 'DBIx::Class::DeploymentHandler' => 'DH';
use Getopt::Long;
use FindBin;
use lib "$FindBin::Bin/../lib";
use OwlcodeAds::Schema;
my $force_overwrite = 1;
unless ( GetOptions( 'force_overwrite!' => \$force_overwrite ) ) {
die "Invalid options";
}
my $schema = OwlcodeAds::Schema->Schema;
my $dh = DH->new(
{
schema => $schema,
script_directory => "$FindBin::Bin/../../dbicdh",
databases => 'PostgreSQL',
sql_translator_args => { add_drop_table => 0 },
force_overwrite => $force_overwrite,
}
);
$dh->prepare_deploy;
eval {
$dh->prepare_upgrade(
{
(
( $OwlcodeAds::Schema::VERSION > 0 )
? (
from_version => $OwlcodeAds::Schema::VERSION - 1,
to_version => $OwlcodeAds::Schema::VERSION
)
: ()
),
}
);
};
if ($@) {
print "$@\n";
$dh->prepare_install;
}

29
script/upgrade.pl Normal file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env perl
use strict;
use warnings;
use aliased 'DBIx::Class::DeploymentHandler' => 'DH';
use Getopt::Long;
use FindBin;
use lib "$FindBin::Bin/../lib";
use OwlcodeAds::Schema;
my $force_overwrite = 1;
unless ( GetOptions( 'force_overwrite!' => \$force_overwrite ) ) {
die "Invalid options";
}
my $schema = OwlcodeAds::Schema->Schema;
my $dh = DH->new(
{
schema => $schema,
script_directory => "$FindBin::Bin/../dbicdh",
databases => 'PostgreSQL',
sql_translator_args => { add_drop_table => 0 },
force_overwrite => $force_overwrite,
}
);
$dh->upgrade;

View File

@ -0,0 +1,12 @@
<html>
<head>
<script src="/js/main.bundle.js"></script>
</head>
<body>
<noscript>
<p>Activa javascript para usar esta web.</p>
</noscript>
<div class="app-container">
</div>
</body>
</html>

30
tsconfig.json Normal file
View File

@ -0,0 +1,30 @@
{
"compilerOptions": {
"outDir": "./public/js/",
"noImplicitAny": true,
"module": "es2020",
"target": "es2020",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node",
"strictNullChecks": true,
"baseUrl": ".",
"paths": {
"@owlads/*": ["js-src/*"],
"/*": ["js-src/*"]
},
"plugins": [
{
"transform": "typescript-transform-paths"
},
{
"transform": "typescript-transform-paths",
"afterDeclarations": true
}
]
},
"include": [
"js-src/*.ts", "js-src/*/*.ts",
"js-src/*.tsx", "js-src/*/*.tsx"
]
}

68
webpack.config.js Normal file
View File

@ -0,0 +1,68 @@
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
entry: './js-src/index.tsx',
mode: 'production',
devtool: 'source-map',
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'public/js/'),
libraryTarget: 'umd',
library: 'main',
umdNamedDefine: true
},
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
roots: [
path.resolve(__dirname, 'js-src/')
],
alias: {
'@owlads': path.resolve(__dirname, 'js-src')
}
},
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.jpe?g|png$/,
exclude: /node_modules/,
use: ['url-loader', 'file-loader']
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
},
optimization: {
minimizer: [
'...',
new CssMinimizerPlugin()
],
}
}