Valse

Un framework MVC pour Vala

a marqué ce sujet comme résolu.

Ne t'inquiète pas, les révisions, je gère ! Et merci pour vos messages de soutient ! :D

Bon en tout cas, j'ai pas réussi à tenir et j'ai testé. Alors déjà j'ai du installer libgee-dev, il faut le préciser. Je suis actuellement sous Ubuntu 15.10. J'ai l'erreur suivante :

1
2
3
4
5
6
7
8
9
user@computer:valse$ bash build.sh 
controller.vala:41.16-41.23: error: The type name `DataBase' could not be found
        public DataBase db () {
               ^^^^^^^^
Compilation failed: 1 error(s), 0 warning(s)

 --- Server is starting ---

build.sh: ligne 7: ./serv: Aucun fichier ou dossier de ce type

Édité par Wizix

+1 -0
Auteur du sujet

@Folaefolc, tu as quoi comme erreurs ?

Sinon essaie sous Windwos 10. Tu as Vala 0.20 ici et un logiciel pour installer les bibliothèques ici. Il faut que tu ajoute libsoup et sqlite. Pour ajouter un package, coche la case tout à droite (si, si, elle est là, scrolle un peu) et fait Update !.

@Wizix, est-ce que tu as pull les dernières modifications ? Par ce que j'ai fait une petite boullette, je viens de m'en rendre compte :-° . Essaie de compiler avec valac *.vala test/*.vala --pkg libsoup-2.4 --pkg gee-1.0 --pkg sqlite3.

+1 -0
Auteur du sujet

En fait Wizix, il vaut mieux que tu déplace tous les fichiers du dossier test (si tu as la dernière version du code) dans la racine du projet, parce que ça crée des bugs imprévus …

+0 -0

Salut !
J'ai pris la toute dernière version sur ton GitLab (là où tu as tout sorti) et voici ce que j'obtiens :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
wala.vala:21.32-21.75: warning: unhandled error `GLib.RegexError'
            Regex include_re = new Regex ("{{ *include '(?P<file>.*)' *}}");
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
wala.vala:29.17-29.58: warning: unhandled error `GLib.FileError'
                get_contents (file_name, out file_content);
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
wala.vala:37.26-37.84: warning: unhandled error `GLib.RegexError'
                result = include_re.replace (result, result.length, 0, file_content);
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
wala.vala:39.26-39.41: warning: unhandled error `GLib.RegexError'
                go_inc = inc_info.next ();
                         ^^^^^^^^^^^^^^^^
wala.vala:42.34-42.98: warning: unhandled error `GLib.RegexError'
            Regex condition_re = new Regex ("{% *if (?P<cond>.*) *%}(?P<content>.*){% *endif *%}");
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
wala.vala:51.27-51.43: warning: unhandled error `GLib.RegexError'
                cond_go = cond_info.next ();
                          ^^^^^^^^^^^^^^^^^
router.vala:18.43-18.58: warning: Soup.SERVER_PORT is deprecated
router.vala:83.13-83.27: warning: Soup.Server.run is deprecated
database.vala:53.38-53.74: warning: unhandled error `GLib.RegexError'
            if (ec != Sqlite.OK && !(new Regex ("table .* already exists").match (errmsg))) {
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
db-set.vala:30.9-30.31: warning: method `Valse.DbSet.check_init' never used
        private bool check_init () {
        ^^^^^^^^^^^^^^^^^^^^^^^
router.vala:29.21-29.26: warning: unreachable code detected
                    break;
                    ^^^^^^
router.vala:32.21-32.26: warning: unreachable code detected
                    break;
                    ^^^^^^
action.vala:7.44-7.47: warning: copying delegates is not supported
controller.vala:64.34-64.44: warning: copying delegates is not supported
/home/louis/valse/router.vala.c: In function ‘valse_router_listen’:
/home/louis/valse/router.vala.c:474:2: warning: ‘soup_server_run’ is deprecated [-Wdeprecated-declarations]
  soup_server_run (_tmp0_);
  ^
In file included from /usr/include/libsoup-2.4/libsoup/soup.h:43:0,
                 from /home/louis/valse/router.vala.c:7:
/usr/include/libsoup-2.4/libsoup/soup-server.h:197:15: note: declared here
 void          soup_server_run                 (SoupServer        *server);
               ^
Compilation succeeded - 14 warning(s)

 --- Server is starting ---


(process:2674): libsoup-CRITICAL **: soup_server_quit: assertion 'priv->listeners != NULL' failed

(process:2674): GLib-GObject-CRITICAL **: object SoupServer 0x141e8a0 finalized while still in-construction

(process:2674): GLib-GObject-CRITICAL **: Custom constructor for class SoupServer returned NULL (which is invalid). Please use GInitable instead.

(process:2674): libsoup-CRITICAL **: soup_server_add_handler: assertion 'SOUP_IS_SERVER (server)' failed

(process:2674): libsoup-CRITICAL **: soup_server_run: assertion 'SOUP_IS_SERVER (server)' failed

Je précise que j'ai du installer le paquet libsoup2.4-dev. J'ai crû comprendre que les warnings était normaux (ce serait bien de tous les corriger quand même.. ;) ). Par contre j'ai le pressentiment que les libsoup-CRITICAL sont un peu moins normaux. Docteur ?

Édité par Wizix

+0 -0
Auteur du sujet

Essaie de mettre ça dans ton fichier router.vala (enlève ce qui y était déjà) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using Soup;
using Gee;
using GLib.FileUtils;
using Sqlite;

namespace Valse {

    public class Router : Object {

        private Server server {get; set;}

        private HashMap<string, Controller> routes {get; set;}

        public static RouterOptions options {get; set; default = new RouterOptions ();}

        public Router (int port = 80) {
            this.routes = new HashMap<string, Controller> ();
            this.server = new Soup.Server();
        }

        private string get_mime (string path) {

            string[] splitted_path = path.split (".");
            string ext = splitted_path [splitted_path.length - 1];

            switch (ext) {
                case "css":
                    return "text/css";
                    break;
                default:
                    return "text/plain";
                    break;

            }
        }

        private string[] split_path (string path) {
            string [] result = new string[] {};
            foreach (string part in path.split("/")) {
                if (part.length != 0) {
                    result += part;
                }
            }

            return result;
        }

        private void soup_handler (Soup.Server server, Soup.Message msg, string path, GLib.HashTable? query, Soup.ClientContext client) {

            print ("Request on %s \n", path);

            string response = "<h1>You found a bug in Valse</h1>";
            string mime = "text/plain";

            string action = "index";
            string[] clean_path = split_path (path);

            try {
                get_contents ("static/" + clean_path [clean_path.length - 1], out response);
                mime = get_mime (path);
            } catch (Error err){
                // Le contrôleur existe
                if (this.routes ["/" + clean_path [0]] != null) {
                    // Si une action est spécifiée ...
                    if (clean_path [clean_path.length - 1] != clean_path [0]) {
                        action = clean_path [clean_path.length - 1];
                    }

                    response = this.routes["/" + clean_path [0]].run_action (action);
                    mime = "text/html";
                }
            }

            msg.set_response (mime, Soup.MemoryUse.COPY, response.data);
        }

        public void register (string route, Controller controller) {
            this.routes.set(route, controller);
            this.server.add_handler (null, soup_handler);
        }

        public void listen () {
            this.server.listen (80, 0);
            this.server.run ();
        }
    }

}

+1 -0
Auteur du sujet

Je ne vous en avait pas encore parlé, mais j'ai un peu amélioré Wala, le moteur de rendu. Vous avez désormais la possibilité d'inclure d'autres fichiers dans votre page, avec cette syntaxe.

1
{% include 'mon-autre-fichier.wala' %}

(Bon en fait, actuellement c'est des {{, mais c'est parce que je me suis trompé, il faut que je fixe ça).

Je suis aussi en train de travailler sur un système de tags. Un tag, c'est comme une condition, sauf qu'il est pré-interprété (ce n'est pas Wala qui fait le travail) parce que je vous avoue que j'avais pas super envie de créer un parseur d'expression booléenne. Au final, vous pourrez donc avoir des pages comme ceci.

1
2
3
4
5
6
7
{% tag 'cache' %}
  <p> Je suis caché </p>
{% endtag %}

{% tag 'coucou' %}
  <p> Tu me vois !</p>
{% endtag %}

Pour préciser un tag, il suffira de faire ceci dans votre action.

1
return page ("fichier.wala", model, ["coucou", "un autre tag", "et un autre"]);

Voilà. J'espère que vous avez finalement pût tester … Moi, je retourne finir le système de tags, si vous avez un problème, n'hésitez pas ! :)

Édité par anonyme

+1 -0
Auteur du sujet

Bonjour tout le monde !

Je continue toujours et encore d'avancer. Les tags sont terminés. Vous avez maintenant la possibilité d'envoyer des fichiers non UTF-8 comme des images, de la musique ou des vidéos (ce qui est pas mal quand même … :-° ). Mais je suis surtout en train de travailler sur des actions améliorées. Vous aurez ainsi la possibilité de définir des headers personalisé pour les réponses, ou de lire ceux de la requête, de définir des codes d'erreur, etc.

On peut envoyer des images

C'est pas encore fini, mais je devrait terminer ça aujourd'hui. Ensuite, je pense que je finirai la gestion des bases de données (UPDATE, DELETE, SELECT *).

Encore une fois, si vous avez des problèmes pour tester, je suis là pour vous aider !

Édité par anonyme

+1 -0
Auteur du sujet

Eeeetttt … les actions complexes fonctionnent ! Vous pourrez donc définir des headers personalisés, connaître la méthode de la requête, l'adresse IP du visiteur, les paramètres (/page/?parametre=test), définir des codes HTTP personalisés, et surement plein d'autre choses qui viendront se rajouter plus tard.

Par exemple, ce code …

1
2
3
4
5
6
7
8
9
// Notre action "évoluée" blob (quel beau nom).
public Response blob (Request req, Response res) {
    ZdSModel model = new ZdSModel ();
    model.greeter = req.query ["msg"];
    res.body = page ("zds.wala", model, new string[] {"yop"}).body;
    res.error_code = 201;
    res.headers["X-Powered-By"] = "Valse";
    return res;
}

Vous permettra d'avoir quelque chose comme ça !

L'url de notre page, avec des paramètres

La page générée en fonction des paramètres

Les headers et le code HTTP personalisés

Édité par anonyme

+2 -0
Auteur du sujet

Petite nouveauté du jour : les filtres.

Les filtres sont des sortes de macros utilisable dans beaucoup de moteur de rendu. J'ai donc décidé de les ajouter à Wala. Par défaut vous avez quatre filtres, mais vous pouvez rajouter les votre si ça vous chante. Ces quatres filtres sont :

  • upper, qui met le texte EN MAJUSCULES.
  • lower, qui le met en minuscule.
  • escape, qui empêche les injections de HTML
  • capitalize, qui rajoute une majuscule au début.

Pour utiliser un filtre, il faut rajouter |nomdufiltre après la variable à laquelle vous voulez l'appliquer.

Si on reprends notre chère page de test (qui va finir par être un gros mélange de toutes les fonctionnalités si je ne la nettoie pas :-° ) et qu'on lui ajoute ça :

1
2
3
4
5
6
7
8
<!-- ... -->
<h1>{{ mod.greeter|upper }}</h1>
<img alt="valse" src="valse.png">
<p>Cette page a été rendue avec {{ render_engine }}.</p>
<p>{{ mod.message|escape }}</p>
<p>{{ mod.question|lower }}</p>
<p>{{ mod.low|capitalize }}</p>
<!-- ... -->

Et cette action :

1
2
3
4
5
6
7
ZdSModel model = new ZdSModel ();
model.greeter = req.query ["msg"] + ", ton IP est " + req.ip;
model.message = "<script>alert('je suis un vilain pirate');</script>";
model.question = "VOUS M'ENTENDEZ ?";
model.low = "je déteste les majuscules";
res.body = page ("zds.wala", model, new string[] {"yop"}).body;
return res;

On arrive à ce résultat :

Nos filtres ont marché, et heureusement sinon une popup serait apparue ...

Édité par anonyme

+2 -0

Cette réponse a aidé l’auteur du sujet

Django fait l'inverse, par défaut tout est échappé et il faut déclarer les chaînes comme étant safe et franchement je trouve ça pas bête et surtout beaucoup plus safe ! Ce qui serait top, c'est que les filtres soient ultra-simple à ajouter, ou qu'on puisse affecter une fonction à un filtre en une ligne !
Autrement bon boulot, il faudrait une doc qui suive la route maintenant ! :-°

+1 -0
Auteur du sujet

@Wizix ah, oui c'est vrai que c'est mieux, je vais changer le filtre escape en safe. Merci pour la suggestion ! ^^

Et pour ajouter des filtres c'est déjà supe simple. Une fois que j'aurai mis la classe Wala en statique (ce que je vais faire juste après normalement) tu aura juste à faire ça :

1
2
3
Wala.add_filter ("monfiltre", (input) => {
    return "Mon filtre >> " + input;
});

Ce qui te donnera pour une variable valant Test., Mon filtre >> Test..

Quand à la doc, je vais surement bientôt la commencer, le code commence à être stable. Mais si tu regardes, j'ai déjà documenté dans le code !

@Folaefolc, pour le moment, le mieux est de cloner le dépôt git et de modifier les fichiers de test, voir en créer d'autres. Mais plus tard, j'envisage de générer un package apt-get et de le rendre facilement installable par poulp. Et après en compilant ça te génère un éxécutable qu'il te suffit de lancer pour avoir ton site en ligne.

Et je suis honoré que tu envisage de prendre Valse pour ton site ! :p

Édité par anonyme

+1 -0

@Wizix ah, oui c'est vrai que c'est mieux, je vais changer le filtre escape en safe. Merci pour la suggestion ! ^^

Bat'

En gros, il disait que toutes les variables passaient dans un filtre escape, et qu'on pouvait passer le filtre safe pour ne pas escape. Je ne suis pas sûr que vous vous soyez bien compris (c'est pour cela que je précise).

Auteur du sujet

Si, si j'avais bie compris. :p Je lui répondait que le filtre escape allait partir et être remplacer par le filtre safe (qui a un code différent). Et escape serait utilisé par défaut.

+1 -0
Auteur du sujet

Le principal intérêt d'avoir un site dynamique est de pouvoir exploiter les données que nous envoit l'utilisateur (messages, articles, commentaires, profil …). Valse permet déjà d'utiliser les paramètres GET (ceux dans l'URL, après le ?), mais pas les paramètres POST … jusqu'à il y a trois quarts d'heure !

Le formulaire

Le résultat !

Pour obtenir ce résultat il vous faudra deux vues : une pour le formualire et une pour afficher le résultat.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Valse test page</title>
    </head>
    <body>
        <h1>Envoyer un message</h1>
        <form method="post">
            <input type="text" name="msg" placeholder="Message">
            <input type="submit" value="Envoyer">
        </form>
    </body>
</html>

formulaire.wala

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Message</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <h2>Vous avez envoyé {{ mod.greeter }}</h2>
    </body>
</html>

message.wala

Ensuite il vous faudra l'action suivante.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
if (req.method == "POST") {
    // Si on reçoit les données du formulaire
    ZdSModel model = new ZdSModel (); 
    // J'utilise ZdSModel parce que j'ai la flemme d'en faire un nouveau
    model.greeter = req.form_data ["msg"]; // On récupère le paramètre POSt 'msg'
    res.body = page ("message.wala", model, {}).body; // On fait le rendu de la page
} else {
    // Sinon, on affiche le formulaire
    res.body = page ("formulaire.wala").body;
}
return res;

Et c'est bon ! Vous pouvez bien sûr avoir un système beaucoup plus complexe, avec plusieurs arguments, un modèle que vous enrgistrez dans votre BDD … La prochaine étape est l'upload de fichiers, et je vais y travailler de ce pas !

Édité par anonyme

+2 -0
Auteur du sujet

Bonne nouvelle, l'upload de fichier marche. Vous pourrez accéder au contenu d'un fichier de la même façon que n'importe quel autre paramètre POST.

J'ai également réussi à compiler Valse en tant que bibliothèque à part. C'est-à-dire que vous n'aurez plus qu'à placer trois/quatres fichiers au bon endroit, puis vous pourrez compiler votre site sans avoir à cloner le dépôt git.

+2 -0

J'adore la façon de faire les formulaires, utiliser directement le champ name est mille fois mieux que la solution de Django où il créé le formulaire pour nous. Dès que je veux personnaliser un peu plus le formulaire c'est un bazar monstrueux. Au moins, chez toi, c'est clair !
J'envisage de plus en plus de faire mon site avec Valse.. :)

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte