Browse Source

Création initiale du projet Amber

master
Olivier DOSSMANN 1 year ago
parent
commit
6d4cadc2ae

+ 4
- 0
.amber.yml View File

@@ -0,0 +1,4 @@
type: app
database: pg
language: slang
model: granite

+ 15
- 0
.gitignore View File

@@ -0,0 +1,15 @@
/doc/
/lib/
/.crystal/
/.shards/
/.vscode/
/tmp/
.env
.encryption_key
production.yml
.DS_Store
/bin/
/node_modules
/public/dist
shard.lock
package-lock.json

+ 12
- 0
Dockerfile View File

@@ -0,0 +1,12 @@
FROM amberframework/amber:v0.9.0

WORKDIR /app

COPY shard.* /app/
RUN shards install

COPY . /app

RUN rm -rf /app/node_modules

CMD amber watch

+ 39
- 2
README.md View File

@@ -1,4 +1,41 @@
# carnetdejeu

Gérer sa collection de jeux vidéos, consoles et figurines.
Et plus si affinités.
Carnet de jeu (CDJ) est une application web permettant de gérer sa collection de jeux vidéos, consoles et figurines.

Site officiel : [https://carnetdejeu.fr/](https://carnetdejeu.fr/)

# Motivation

L'idée principale de ce projet est d'avoir - enfin - un site web francophone concernant sa collection de jeux vidéos.

Mais également d'avoir une alternative OpenSource au très connu Backloggery.com.

# Pré-requis

* Crystal 0.26.0
* Amber 0.9.0
* shards 0.8.1

# Installation des dépendances Crystal

```bash
shards install
```

# Aperçu de l'application

```
amber w
```

# Fabriqué avec

* [Amber](https://amberframework.org/) - framework pour créer des applications simples, rapides et agréables

# Contributeurs

* Olivier DOSSMANN - création initiale - [blankoworld](https://github.com/blankoworld/)

# Licence

Ce projet est délivré sous les termes de la licence EUPL 1.2. Pour plus d’informations, veuillez lire [la licence EUPL 1.2](https://joinup.ec.europa.eu/collection/eupl/eupl-text-11-12).

+ 131
- 0
config/application.cr View File

@@ -0,0 +1,131 @@
require "./initializers/**"

require "amber"

require "../src/controllers/application_controller"
require "../src/controllers/**"

# About Application.cr File
#
# This is Amber application main entry point. This file is responsible for loading
# initializers, classes, and all application related code in order to have
# Amber::Server boot up.
#
# > We recommend to not modify the order of the require since the order will
# affect the behavior of the application.
#
# With `Amber::Server.configure` block you can redefine the Server configuration
# settings and use ENVIRONMENT variables and/or values evaluated at runtime.
#
# > Important! Yaml configurations are first class citizen and are loaded first before
# this file, we recommend to use yaml configurations before changing any settings here.
# Any uncommented setting here will override the YAML with the value set here.

Amber::Server.configure do |settings|
# Use your environment variables settings here.
#
# Name: A name that identifies this application. This is not internally
# used by the framework.
#
# settings.name = "Cdj Carnetdejeu web application."
#
#
# Colorize Logging: specifies whether or not to use ANSI color codes
# when logging information, display the time and/or to display the severity level.
# Defaults to true.
#
# Log Level defines the verbosity of the Amber logger. This option defaults to
# debug for all environments. The available log levels are: debug, info, warn,
# error, fatal, and unknown.
#
# settings.logging.colorize = true
# settings.logging.severity = "debug"
# settings.logging.filter = %w(password confirm_password)
# settings.logging.skip = %w()
# settings.logging.context = %w(request headers cookies session params)
#
#
# Secret Key Base: is used for specifying a key which allows sessions
# for the application to be verified against a known secure key to
# prevent tampering. Applications get Amber.secret_key
# initialized to a random key present in `ENV["AMBER_SECRET_KEY"]` or
# `.amber_secret_key` in this order.
#
# settings.secret_key_base= FEHWm3Fpm7vrPejFPM9x-3PLkj7C_fho6N-nIaBa19g
#
#
# Host: is the application server host address or ip address. Useful for when
# deploying Amber to a PAAS and likely the assigned server IP is either
# known or unknown. Defaults to an environment variable HOST
#
# settings.host = ENV["HOST"] if ENV["HOST"]?
#
#
# Port Reuse: Amber supports clustering mode which allows to spin
# multiple app instances per core. This setting allows to bind the different
# instances to the same port. Default this setting to true if the number or process
# is greater than 1.
#
# > Read more about Linux PORT REUSE https://lwn.net/Articles/542629/
#
# settings.port_reuse = true
#
#
# Process Count: This will enable Amber to be used in cluster mode,
# spinning an instance for each number of process specified here.
# Rule of thumb, always leave at least 1 core available for system processes/resources.
#
# settings.process_count = ENV["PROCESS_COUNT"].to_i if ENV["PROCESS_COUNT"]?
#
#
# PORT: This is the port that you're application will run on. Examples would be (80, 443, 3000, 8080)
#
settings.port = ENV["PORT"].to_i if ENV["PORT"]?
#
#
# Redis URL: Redis is an in memory key value storage. Amber utilizes redis as
# a storing option for session information.
#
# settings.redis_url = ENV["REDIS_URL"] if ENV["REDIS_URL"]?
#
#
# Database URL: This is the database connection string or data file url.
# The connection string contains the information to establish a connection to the
# database or the data file. Defaults to the database provider you chose at
# at app generation.
#
# settings.database_url = ENV["DATABASE_URL"] if ENV["DATABASE_URL"]?
#
#
# SSL Key File: The private key is a text file used initially to generate a
# Certificate Signing Request (CSR), and later to secure and verify connections
# using the certificate created per that request. The private key is used to create
# a digital signature as you might imagine from the name, the private key should be
# ``closely guarded.
#
# settings.ssl_key_file = ENV["SSL_KEY_FILE"] if ENV["SSL_KEY_FILE"]?
#
#
# SSL Cert File: This represents the signed certificate file. SSL Certificates are
# small data files that digitally bind a cryptographic key to an organization's
# details. When installed on a web server, it activates the padlock and the https
# protocol and allows secure connections from a web server to a browser.
#
# settings.ssl_cert_file = ENV["SSL_CERT_FILE"] if ENV["SSL_CERT_FILE"]?
#
#
# Session: A Hash that specifies the session storage mechanism, expiration and key to be used
# for the application. The `key` specifies the name of the cookie to be used defaults to
# "amber.session". The store can be `encrypted_cookie`, `signed_cookie` or `redis`. Expires
# when set to 0 means this is indefinitely and is expressed in seconds.
#
# settings.session = { "key" => "amber.session", "store" => "signed_cookie", "expires" => 0 }
#
#
# Logger: is the logger that Amber and other capable shards in the project will use
# instead of writing directly to STDOUT. Supply a custom logger to write to syslog, etc.
#
# settings.logger = Amber::Environment::Logger.new(File.open("cdj_carnetdejeu.log", "w"))
#
#
end

BIN
config/environments/.production.enc View File


+ 36
- 0
config/environments/development.yml View File

@@ -0,0 +1,36 @@
secret_key_base: cie0hbJtXS-F51akAYdEeNof67tLG4q-L5bpaLqgPTE
port: 3000
name: cdj_carnetdejeu

logging:
severity: debug
colorize: true
filter:
- password
- confirm_password
context:
- request
- session
- headers
- cookies
- params

host: 0.0.0.0
port_reuse: true
process_count: 1
# ssl_key_file:
# ssl_cert_file:
redis_url: "redis://localhost:6379"
database_url: postgres://postgres:@localhost:5432/cdj_carnetdejeu_development

session:
key: amber.session
store: signed_cookie
expires: 0

smtp:
enabled: false

secrets:
description: Store your development secrets credentials and settings here.


+ 36
- 0
config/environments/test.yml View File

@@ -0,0 +1,36 @@
secret_key_base: 2jEkAoKdioIl6U1W0T-Zu2U7V5HRQ3-GpeIxOeEVjms
port: 3000
name: cdj_carnetdejeu

logging:
severity: debug
colorize: true
filter:
- password
- confirm_password
context:
- request
- session
- headers
- cookies
- params

host: 0.0.0.0
port_reuse: false
process_count: 1
# ssl_key_file:
# ssl_cert_file:
redis_url: "redis://localhost:6379"
database_url: postgres://postgres:@localhost:5432/cdj_carnetdejeu_test

session:
key: amber.session
store: signed_cookie
expires: 0

smtp:
enabled: false

secrets:
description: Store your development secrets credentials and settings here.


+ 6
- 0
config/initializers/database.cr View File

@@ -0,0 +1,6 @@
require "granite/adapter/pg"

Granite::Adapters << Granite::Adapter::Pg.new({name: "pg", url: Amber.settings.database_url})
Granite.settings.logger = Amber.settings.logger.dup
Granite.settings.logger.progname = "Granite"


+ 24
- 0
config/initializers/i18n.cr View File

@@ -0,0 +1,24 @@
require "citrine-i18n"

Citrine::I18n.configure do |settings|
# Backend storage (as supported by i18n.cr)
# settings.backend = I18n::Backend::Yaml.new

# Default locale (defaults to "en" and "./src/locales/**/en.yml").
# For a new default locale to be accepted, it must be found by the
# backend storage and reported in "settings.available_locales".
# settings.default_locale = "en"

# Separator between sublevels of data (defaults to '.')
# e.g. I18n.translate("some/thing") instead of "some.thing"
# settings.default_separator = '.'

# Returns the current exception handler. Defaults to an instance of
# I18n::ExceptionHandler.
# settings.exception_handler = ExceptionHandler.new

# The path from where the translations should be loaded
settings.load_path += ["./src/locales"]
end

I18n.init

+ 42
- 0
config/routes.cr View File

@@ -0,0 +1,42 @@
Amber::Server.configure do
pipeline :web do
# Plug is the method to use connect a pipe (middleware)
# A plug accepts an instance of HTTP::Handler
plug Amber::Pipe::PoweredByAmber.new
# plug Amber::Pipe::ClientIp.new(["X-Forwarded-For"])
plug Citrine::I18n::Handler.new
plug Amber::Pipe::Error.new
plug Amber::Pipe::Logger.new
plug Amber::Pipe::Session.new
plug Amber::Pipe::Flash.new
plug Amber::Pipe::CSRF.new
end

pipeline :api do
plug Amber::Pipe::PoweredByAmber.new
plug Amber::Pipe::Error.new
plug Amber::Pipe::Logger.new
plug Amber::Pipe::Session.new
plug Amber::Pipe::CORS.new
end

# All static content will run these transformations
pipeline :static do
plug Amber::Pipe::PoweredByAmber.new
plug Amber::Pipe::Error.new
plug Amber::Pipe::Static.new("./public")
end

routes :web do
get "/", HomeController, :index
end

routes :api do
end

routes :static do
# Each route is defined as follow
# verb resource : String, controller : Symbol, action : Symbol
get "/*", Amber::Controller::Static, :index
end
end

+ 69
- 0
config/webpack/common.js View File

@@ -0,0 +1,69 @@
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

let config = {
entry: {
'main.bundle.js': './src/assets/javascripts/main.js',
'main.bundle.css': './src/assets/stylesheets/main.scss'
},
output: {
filename: '[name]',
path: path.resolve(__dirname, '../../public/dist'),
publicPath: '/dist'
},
resolve: {
alias: {
amber: path.resolve(__dirname, '../../lib/amber/assets/js/amber.js')
}
},
module: {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'sass-loader']
})
},
{
test: /\.(png|svg|jpg|gif)$/,
exclude: /node_modules/,
use: [
'file-loader?name=/images/[name].[ext]'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
exclude: /node_modules/,
use: [
'file-loader?name=/[name].[ext]'
]
},
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['env']
}
}
]
},
plugins: [
new ExtractTextPlugin('main.bundle.css'),
],
// For more info about webpack logs see: https://webpack.js.org/configuration/stats/
stats: 'errors-only'
};

module.exports = config;

+ 7
- 0
config/webpack/development.js View File

@@ -0,0 +1,7 @@
const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./common.js');

module.exports = merge(common, {
devtool: 'inline-source-map'
});

+ 11
- 0
config/webpack/production.js View File

@@ -0,0 +1,11 @@
const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./common.js');

module.exports = merge(common, {
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false }
})
]
});

+ 0
- 0
db/migrations/.gitkeep View File


+ 42
- 0
docker-compose.yml View File

@@ -0,0 +1,42 @@
version: '2'

services:
app:
build: .
image: cdj_carnetdejeu
command: amber watch
environment:
DATABASE_URL: postgres://admin:password@db:5432/cdj_carnetdejeu_development
ports:
- 3000:3000
links:
- db
volumes:
- .:/app
- nodes:/app/node_modules
- shards:/app/lib

migrate:
build: .
image: cdj_carnetdejeu
command: bash -c 'while ! nc -q 1 db 5432 </dev/null; do sleep 1; done && amber db migrate seed'
environment:
DATABASE_URL: postgres://admin:password@db:5432/cdj_carnetdejeu_development
volumes:
- .:/app
links:
- db

db:
image: postgres
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: password
POSTGRES_DB: cdj_carnetdejeu_development
volumes:
- db:/var/lib/postgres/data

volumes:
db:
nodes:
shards:

+ 27
- 0
package.json View File

@@ -0,0 +1,27 @@
{
"name": "cdj_carnetdejeu",
"version": "0.1.0",
"description": "Cdj Carnetdejeu with Amber",
"private": true,
"author": "Olivier DOSSMANN",
"license": "UNLICENSED",
"scripts": {
"build": "webpack --config config/webpack/development.js",
"watch": "webpack -w --config config/webpack/development.js",
"release": "webpack -p --config config/webpack/production.js",
"test": "echo \"No test specified\" && exit 1"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.6.1",
"css-loader": "^0.28.11",
"file-loader": "^1.1.11",
"node-sass": "^4.9.0",
"sass-loader": "^7.0.1",
"style-loader": "^0.21.0",
"webpack": "^3.12.0",
"webpack-merge": "^4.1.2",
"extract-text-webpack-plugin": "^3.0.2"
}
}

+ 15
- 0
public/crossdomain.xml View File

@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<!-- Read this: www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html -->

<!-- Most restrictive policy: -->
<site-control permitted-cross-domain-policies="none"/>

<!-- Least restrictive policy: -->
<!--
<site-control permitted-cross-domain-policies="all"/>
<allow-access-from domain="*" to-ports="*" secure="false"/>
<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
-->
</cross-domain-policy>

BIN
public/favicon.ico View File


BIN
public/favicon.png View File


+ 3
- 0
public/robots.txt View File

@@ -0,0 +1,3 @@
# http://www.robotstxt.org
User-agent: *
Disallow:

+ 47
- 0
shard.yml View File

@@ -0,0 +1,47 @@
name: cdj_carnetdejeu
version: 0.1.0

authors:
- Olivier DOSSMANN <git@dossmann.net>

crystal: 0.26.0

license: UNLICENSED

targets:
cdj_carnetdejeu:
main: src/cdj_carnetdejeu.cr

amber:
main: lib/amber/src/amber/cli.cr

dependencies:
amber:
github: amberframework/amber
version: 0.9.0
#branch: master

granite:
github: amberframework/granite
version: ~> 0.13.0

quartz_mailer:
github: amberframework/quartz-mailer
version: ~> 0.5.1

jasper_helpers:
github: amberframework/jasper-helpers
version: ~> 0.2.0

pg:
github: will/crystal-pg
version: ~> 0.15.0

citrine-i18n:
github: amberframework/citrine-i18n
version: 0.3.2

development_dependencies:
garnet_spec:
github: amberframework/garnet-spec
version: ~> 0.2.1

+ 16
- 0
spec/spec_helper.cr View File

@@ -0,0 +1,16 @@
ENV["AMBER_ENV"] ||= "test"

require "spec"
require "micrate"
require "garnet_spec"

require "../config/*"

Micrate::DB.connection_url = Amber.settings.database_url

# Automatically run migrations on the test database
Micrate::Cli.run_up

# Disable Granite logs in tests
Granite.settings.logger = Logger.new nil


+ 0
- 0
src/assets/fonts/.gitkeep View File


+ 0
- 0
src/assets/images/.gitkeep View File


BIN
src/assets/images/logo.png View File


+ 23
- 0
src/assets/javascripts/main.js View File

@@ -0,0 +1,23 @@
import Amber from 'amber'

if (!Date.prototype.toGranite) {
(function() {

function pad(number) {
if (number < 10) {
return '0' + number;
}
return number;
}

Date.prototype.toGranite = function() {
return this.getUTCFullYear() +
'-' + pad(this.getUTCMonth() + 1) +
'-' + pad(this.getUTCDate()) +
' ' + pad(this.getUTCHours()) +
':' + pad(this.getUTCMinutes()) +
':' + pad(this.getUTCSeconds()) ;
};

}());
}

+ 117
- 0
src/assets/stylesheets/main.scss View File

@@ -0,0 +1,117 @@
$font-stack: "Helvetica Neue", Helvetica, Arial, sans-serif;
$background-color: #f4994b;
$nav-item-color: #ffe4cd;

/*
* Globals
*/
body {
font-family: $font-stack;
color: #555;
}

h1, .h1,
h2, .h2,
h3, .h3,
h4, .h4,
h5, .h5,
h6, .h6 {
margin-top: 0;
font-family: $font-stack;
font-weight: normal;
color: #333;
}

/*
* Override Bootstrap's default container.
*/
@media (min-width: 1200px) {
.container {
width: 970px;
}
}

/*
* Masthead for nav
*/
.masthead {
background-color: $background-color;
-webkit-box-shadow: inset 0 -2px 5px rgba(0,0,0,.1);
box-shadow: inset 0 -2px 5px rgba(0,0,0,.1);
}

/* Nav links */
.nav-item {
position: relative;
display: inline-block;
padding: 10px;
font-weight: 500;
color: $nav-item-color;
}
.nav-item:hover,
.nav-item:focus {
color: #fff;
text-decoration: none;
}

/* Active state gets a caret at the bottom */
.nav .active {
color: #fff;
}
.nav .active:after {
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 0;
margin-left: -5px;
vertical-align: middle;
content: " ";
border-right: 5px solid transparent;
border-bottom: 5px solid;
border-left: 5px solid transparent;
}

.main {
padding-top: 20px;
}

#logo {
background-color: $background-color;
background-image: url("../images/logo.png");
background-size:contain;
width: 200px;
height:278px;
}

/* Hide logo in small screens */
@media (max-width: 767px) {
#logo {
display: none;
}
}

.table td, .table th {
vertical-align: middle;
}

.alert {
margin-top: 1em;

p {
margin-top: 0;
margin-bottom: 0;
}
}

// For Navigation pulling right
.nav-item-auth {
&.nav-item-auth-signout, &.nav-item-auth-signup {
order: 9999;
}

&.nav-item-auth-profile, &.nav-item-auth-signin {
order: 9990;
margin-left: auto;
}
}

+ 3
- 0
src/cdj_carnetdejeu.cr View File

@@ -0,0 +1,3 @@
require "../config/*"

Amber::Server.start

+ 6
- 0
src/controllers/application_controller.cr View File

@@ -0,0 +1,6 @@
require "jasper_helpers"

class ApplicationController < Amber::Controller::Base
include JasperHelpers
LAYOUT = "application.slang"
end

+ 5
- 0
src/controllers/home_controller.cr View File

@@ -0,0 +1,5 @@
class HomeController < ApplicationController
def index
render("index.slang")
end
end

+ 2
- 0
src/locales/en.yml View File

@@ -0,0 +1,2 @@
---
welcome_to_amber: "Welcome to Amber Framework!"

+ 9
- 0
src/views/home/index.slang View File

@@ -0,0 +1,9 @@
.row
#logo
.col-sm-12.col-md-6
h2 = t "welcome_to_amber"
p Thank you for trying out the Amber Framework. We are working hard to provide a super fast and reliable framework that provides all the productivity tools you are used to without sacrificing the speed.
.list-group
a.list-group-item.list-group-item-action target="_blank" href="https://docs.amberframework.org" Getting Started with Amber Framework
a.list-group-item.list-group-item-action target="_blank" href="https://github.com/veelenga/awesome-crystal" List of Awesome Crystal projects and shards
a.list-group-item.list-group-item-action target="_blank" href="https://crystalshards.xyz" What's hot in Crystal right now

+ 2
- 0
src/views/layouts/_nav.slang View File

@@ -0,0 +1,2 @@
- active = context.request.path == "/" ? "active" : ""
a class="nav-item #{active}" href="/" Home

+ 32
- 0
src/views/layouts/application.slang View File

@@ -0,0 +1,32 @@
doctype html
html
head
title Cdj Carnetdejeu using Amber
meta charset="utf-8"
meta http-equiv="X-UA-Compatible" content="IE=edge"
meta name="viewport" content="width=device-width, initial-scale=1"
link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
link rel="stylesheet" href="/dist/main.bundle.css"
link rel="apple-touch-icon" href="/favicon.png"
link rel="icon" href="/favicon.png"
link rel="icon" type="image/x-icon" href="/favicon.ico"

body
.masthead
.container
nav.nav
== render(partial: "layouts/_nav.slang")
.container
.row
.col-sm
- flash.each do |key, value|
div class="alert alert-#{key}"
p = flash[key]
.row
.col-sm-12.main
== content

script src="https://code.jquery.com/jquery-3.3.1.min.js"
script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"
script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"
script src="/dist/main.bundle.js"

Loading…
Cancel
Save