Site icon Maniac Geek

Créez votre propre SaaS sur Linux avec Vely

Vely combine les hautes performances et la faible empreinte du C avec la facilité d’utilisation et la sécurité améliorée des langages comme PHP. C’est un logiciel gratuit et open source, sous licence GPLv3 et LGPL 3 pour les bibliothèques, vous pouvez donc même créer des logiciels commerciaux avec.

Utilisation de Vely pour le SaaS

Vous pouvez utiliser Vely pour créer une application Web mutualisée que vous pouvez exécuter sur Internet en tant que logiciel en tant que service (SaaS). Chaque utilisateur dispose d’un espace de données complètement séparé de tout autre.

Dans cet exemple d’application Web, un utilisateur peut s’inscrire à un service de bloc-notes pour créer des notes, puis les afficher et les supprimer. Il démontre plusieurs intégrations technologiques en seulement 310 lignes de code dans sept fichiers source. Les technologies incluent :

  • MariaDB
  • Navigateur Web
  • apache
  • Prises Unix

Comment ça fonctionne

Voici comment l’application fonctionne du point de vue de l’utilisateur. Un code pas à pas suit les images.

L’application permet à un utilisateur de créer une nouvelle connexion en spécifiant une adresse e-mail et un mot de passe. Vous pouvez les styliser comme bon vous semble, comme avec CSS :

(Sergio Mijatovic, CC BY-SA 4.0)

Vérifiez l’adresse e-mail de l’utilisateur :

(Sergio Mijatovic, CC BY-SA 4.0)

Chaque utilisateur se connecte avec son nom d’utilisateur et son mot de passe uniques :

(Sergio Mijatovic, CC BY-SA 4.0)

Une fois connecté, un utilisateur peut ajouter une note :

(Sergio Mijatovic, CC BY-SA 4.0)

Un utilisateur peut obtenir une liste de notes :

(Sergio Mijatovic, CC BY-SA 4.0)

L’application demande confirmation avant de supprimer une note :

(Sergio Mijatovic, CC BY-SA 4.0)

Après confirmation de l’utilisateur, la note est supprimée :

(Sergio Mijatovic, CC BY-SA 4.0)

Conditions préalables à l’installation

Suivez les instructions d’installation sur Vely.dev. Il s’agit d’un processus rapide qui utilise des outils d’empaquetage standard, tels que DNF, APT, Pacman ou Zypper.

Comme ils font partie de cet exemple, vous devez installer Apache en tant que serveur Web et MariaDB en tant que base de données.

Après avoir installé Vely, activez la coloration syntaxique dans Vim si vous l’utilisez :

vv -m

Obtenir le code source

Le code source de cette application SaaS de démonstration fait partie de l’installation de Vely. C’est une bonne idée de créer un répertoire de code source séparé pour chaque application (et vous pouvez le nommer comme vous le souhaitez). Dans ce cas, décompresser le code source le fait pour vous :

$ tar xvf $(vv -o)/examples/multitenant_SaaS.tar.gz
$ cd multitenant_SaaS

Par défaut, l’application s’appelle multitenant_SaaSmais vous pouvez l’appeler n’importe quoi (si vous faites cela, changez-le partout).

Configurer l’application

La toute première étape consiste à créer une application. C’est simple à faire avec Vely’s vf utilitaire:

$ sudo vf -i -u $(whoami) multitenant_SaaS

Cette commande crée un nouvel accueil d’application (/var/lib/vv/multitenant_SaaS) et effectue la configuration de l’application pour vous. Cela signifie principalement créer divers sous-répertoires dans le dossier de départ et attribuer des privilèges. Dans ce cas, seul l’utilisateur actuel (le résultat de whoami) possède les répertoires, avec les privilèges 0700, ce qui garantit que personne d’autre n’a accès aux fichiers.

Configurer la base de données

Avant de procéder à tout codage, vous avez besoin d’un emplacement pour stocker les informations utilisées par l’application. Tout d’abord, créez une base de données MariaDB appelée db_multitenant_SaaSpropriété de l’utilisateur vely avec mot de passe your_password. Vous pouvez modifier n’importe laquelle de ces valeurs, mais n’oubliez pas de les modifier partout dans cet exemple.

Connecté en tant que root dans l’utilitaire MySQL :

CREATE DATABASE IF NOT EXISTS db_multitenant_SaaS;
CREATE USER IF NOT EXISTS vely IDENTIFIED BY 'your_password';
GRANT CREATE,ALTER,DROP,SELECT,INSERT,DELETE,UPDATE ON db_multitenant_SaaS.* TO vely;

Créez ensuite des objets de base de données (tables et enregistrements, etc.) dans la base de données :

USE db_multitenant_SaaS;
SOURCE setup.sql;
exit

Connecter Vely à une base de données

Pour que Vely sache où se trouve votre base de données et comment s’y connecter, créez un fichier de configuration de base de données nommé db_multitenant_SaaS. (C’est le nom utilisé par les instructions de base de données dans le code source, donc si vous le modifiez, assurez-vous de le changer partout.)

Vely utilise la connectivité native de la base de données MariaDB, vous pouvez donc spécifier toutes les options qu’une base de données donnée vous permet :

$ echo '[client]
user=vely
password=your_password
database=db_multitenant_SaaS
protocol=TCP
host=127.0.0.1
port=3306'
> db_multitenant_SaaS

Construire l’application

Utilisez le vv utilitaire pour faire l’application, en utilisant le --db option pour spécifier la base de données MariaDB et le fichier de configuration de la base :

$ vv -q --db=mariadb:db_multitenant_SaaS

Programmation et développement

Démarrer le serveur d’applications

Pour démarrer le serveur d’applications de votre application Web, utilisez le vf Gestionnaire de processus FastCGI. Le serveur d’application utilise un socket Unix pour communiquer avec le serveur web (création d’un reverse proxy) :

$ vf -w 3 multitenant_SaaS

Cela démarre trois processus démons pour traiter les demandes entrantes. Vous pouvez également démarrer un serveur adaptatif qui augmente le nombre de processus pour traiter plus de requêtes et réduire progressivement le nombre de processus lorsqu’ils ne sont pas nécessaires :

$ vf multitenant_SaaS

Voir vf pour plus d’options pour vous aider à obtenir les meilleures performances.

Lorsque vous devez arrêter votre serveur d’applications, utilisez le -m quit option:

$ vf -m quit multitenant_SaaS

Configurer le serveur Web

Il s’agit d’une application Web, donc l’application a besoin d’un serveur Web. Cet exemple utilise Apache au moyen d’un écouteur de socket Unix.

1. Configurer Apache

Pour configurer Apache en tant que proxy inverse et y connecter votre application, vous devez activer le support du proxy FastCGI, ce qui signifie généralement utiliser le proxy et proxy_fcgi modules.

Pour les systèmes Fedora (ou autres, comme Arch), activez le proxy et proxy_fcgi modules en ajoutant (ou décommentant) les ChargerModule directives dans le /etc/httpd/conf/httpd.conf Fichier de configuration apache.

Pour Debian, Ubuntu et des systèmes similaires, activez le proxy et proxy_fcgi modules:

$ sudo a2enmod proxy
$ sudo a2enmod proxy_fcgi

Pour OpenSUSE, ajoutez ces lignes à la fin de /etc/apache2/httpd.conf:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so

2. Configurez Apache

Vous devez maintenant ajouter les informations de proxy au fichier de configuration Apache :

ProxyPass "/multitenant_SaaS" unix:///var/lib/vv/multitenant_SaaS/sock/sock|fcgi://localhost/multitenant_SaaS

L’emplacement de votre configuration peut varier en fonction de votre distribution Linux :

  • Fedora, CentOS, Mageia et Arch : /etc/httpd/conf/httpd.conf
  • Debian, Ubuntu, Menthe : /etc/apache2/apache2.conf
  • OuvrirSUSE : /etc/apache2/httpd.conf

3. Redémarrez

Enfin, redémarrez Apache. Sur Fedora et systèmes similaires, ainsi que Arch Linux :

$ sudo systemctl restart httpd

Sur les systèmes Debian et basés sur Debian, ainsi que sur OpenSUSE :

$ sudo systemctl restart apache2

Configurer la messagerie locale

Cet exemple utilise le courrier électronique dans le cadre de sa fonction. Si votre serveur peut déjà envoyer des e-mails, vous pouvez ignorer cette étape. Sinon, vous pouvez utiliser le courrier local (myuser@localhost) juste pour tester. Pour ce faire, installez Sendmail.

Sur Fedora et similaire :

$ sudo dnf install sendmail
$ sudo systemctl start sendmail

Sur les systèmes Debian (comme Ubuntu) :

$ sudo apt install sendmail
$ sudo systemctl start sendmail

Lorsque l’application envoie un e-mail à un utilisateur local, tel que OS_user@localhostvous pouvez alors vérifier que l’e-mail a bien été envoyé en consultant /var/mail/ (le « spool de courrier »).

Accéder au serveur d’application depuis le navigateur

En supposant que vous exécutez l’application localement, utilisez http://127.0.0.1/multitenant_SaaS?req=notes&action=begin pour accéder à votre serveur d’application à partir de votre navigateur Web. Si vous l’exécutez sur un serveur en direct sur Internet, vous devrez peut-être ajuster les paramètres de votre pare-feu pour autoriser le trafic HTTP.

Code source

Cet exemple d’application contient sept fichiers sources. Vous pouvez revoir le code vous-même (rappelez-vous, il ne s’agit que de 310 lignes dans ces fichiers), mais voici un aperçu de chacun.

Configuration SQL (setup.sql)

Les deux tables créées sont :

  • utilisateurs: Informations sur chaque utilisateur. Chaque utilisateur du utilisateurs table a son propre ID unique (identifiant d’utilisateur colonne) ainsi que d’autres informations telles que l’adresse e-mail et si elle est vérifiée. Il y a aussi un mot de passe haché. Un mot de passe réel n’est jamais stocké en texte brut (ou autrement); un hachage unidirectionnel est utilisé pour vérifier le mot de passe.
  • Remarques: Notes saisies par l’utilisateur. La Remarques table contient les notes, chacune avec identifiant d’utilisateur colonne qui indique quel utilisateur les possède. La identifiant d’utilisateur la valeur de la colonne correspond à la colonne homonyme de utilisateurs table. De cette façon, chaque note appartient clairement à un seul utilisateur.

Le contenu du fichier :

CREATE TABLE IF NOT EXISTS notes (dateOf datetime, noteId BIGINT AUTO_INCREMENT PRIMARY KEY, userId BIGINT, note VARCHAR(1000));
CREATE TABLE IF NOT EXISTS users (userId BIGINT AUTO_INCREMENT PRIMARY KEY, email VARCHAR(100), hashed_pwd VARCHAR(100), verified SMALLINT, verify_token VARCHAR(30), SESSION VARCHAR(100));
CREATE UNIQUE INDEX IF NOT EXISTS users1 ON users (email);

Données d’exécution (login.h)

Pour afficher correctement les liens de connexion, d’inscription et de déconnexion, vous avez besoin de certains indicateurs disponibles n’importe où dans l’application. De plus, l’application utilise des cookies pour maintenir une session, donc cela doit être disponible n’importe où, par exemple, pour vérifier que la session est valide. Chaque demande envoyée à l’application est ainsi confirmée. Seules les demandes accompagnées de cookies vérifiables sont autorisées.

Donc, à cet effet, vous avez un global_request_data taper reqdata (demande de données) et dedans il y a sess_userId (ID de l’utilisateur) et sess_id (ID de session en cours de l’utilisateur). Vous avez également des drapeaux plutôt explicites qui aident à rendre les pages :

#ifndef _VV_LOGIN
#define _VV_LOGIN

typedef struct s_reqdata {
    bool displayed_logout; // true if Logout link displayed
    bool is_logged_in; // true if session verified logged-in
    char *sess_userId; // user ID of current session
    char *sess_id; // session ID
} reqdata;

void login_or_signup ();

#endif

Vérification de session et données de session (_before.vely)

Vely a la notion d’un avant_request_handler. Le code que vous écrivez s’exécute avant tout autre code qui gère une requête. Pour cela, il suffit d’écrire ce code dans un fichier nommé _before.velyet le reste est automatiquement géré.

Tout ce que fait une application SaaS, comme la gestion des demandes envoyées à une application, doit être validé pour des raisons de sécurité. De cette façon, l’application sait si l’appelant dispose des autorisations nécessaires pour effectuer une action.

La vérification de l’autorisation est effectuée ici dans un gestionnaire de requête avant. De cette façon, quel que soit l’autre code dont vous disposez pour gérer une requête, vous disposez déjà des informations de session.

Pour garder les données de session (comme l’ID de session et l’ID utilisateur) disponibles n’importe où dans votre code, vous utilisez global_request_data. C’est juste un pointeur générique (annuler*) à la mémoire à laquelle tout code qui gère les requêtes peut accéder. C’est parfait pour les sessions de manipulation, comme indiqué ci-dessous :

#include "vely.h"
#include "login.h"

// _before() is a before-request-handler. It always executes before
// any other code that handles a request. It's a good place for any
// kind of request-wide setting or data initialization
void _before() {
    // Output HTTP header
    out-header default
    reqdata *rd; // this is global request data, see login.h
    // allocate memory for global request data, will be automatically deallocated
    // at the end of request
    new-mem rd size sizeof(reqdata)
    // initialize flags
    rd->displayed_logout = false;
    rd->is_logged_in = false;
    // set the data we created to be global request data, accessible
    // from any code that handles a request
    set-req data rd
    // check if session exists (based on cookies from the client)
    // this executes before any other request-handling code, making it
    // easier to just have session information ready
    _check_session ();
}

Vérifier si la session est valide (_check_session.vely)

L’une des tâches les plus importantes dans une application SaaS mutualisée consiste à vérifier (dès que possible) si la session est valide en vérifiant si un utilisateur est connecté. Cela se fait en obtenant les cookies d’ID de session et d’ID utilisateur du client (tels que en tant que navigateur Web) et en les comparant à la base de données dans laquelle les sessions sont stockées :

#include "vely.h"
#include "login.h"

// Check if session is valid
void _check_session () {
    // Get global request data
    reqdata *rd;
    get-req data to rd
    // Get cookies from user browser
    get-cookie rd->sess_userId="sess_userId"
    get-cookie rd->sess_id="sess_id"
    if (rd->sess_id[0] != 0) {
        // Check if session ID is correct for given user ID
        char *email;
        run-query @db_multitenant_SaaS = "select email from users where userId='%s' and session='%s'" output email : rd->sess_userId, rd->sess_id row-count define rcount
            query-result email to email
        end-query
        if (rcount == 1) {
            // if correct, set logged-in flag
            rd->is_logged_in = true;
            // if Logout link not display, then display it
            if (rd->displayed_logout == false) {
                @Hi <<p-out email>>! <a href="https://opensource.com/?req=login&action=logout">Logout</a><br/>
                rd->displayed_logout = true;
            }
        } else rd->is_logged_in = false;
    }
}

Inscription, connexion, déconnexion (login.vely)

La base de tout système mutualisé est la possibilité pour un utilisateur de s’inscrire, de se connecter et de se déconnecter. En règle générale, l’inscription implique la vérification de l’adresse e-mail ; le plus souvent, la même adresse e-mail est utilisée comme nom d’utilisateur. C’est le cas ici.

Plusieurs sous-requêtes implémentées ici sont nécessaires pour exécuter la fonctionnalité :

  • Lors de l’inscription d’un nouvel utilisateur, affichez le formulaire HTML pour collecter les informations. La signature de la demande d’URL pour cela est req=login&action=newuser.
  • En réponse au formulaire d’inscription, créez un nouvel utilisateur. La signature de la demande d’URL est req=login&action=createuser. La paramètre d’entrée le signal obtient un e-mail et pwd Champs de formulaire POST. La valeur du mot de passe est un hachage unidirectionnel et un jeton de vérification d’e-mail est créé sous la forme d’un nombre aléatoire à cinq chiffres. Ceux-ci sont insérés dans le utilisateurs table, créant un nouvel utilisateur. Un e-mail de vérification est envoyé et l’utilisateur est invité à lire l’e-mail et à saisir le code.
  • Vérifiez l’e-mail en entrant le code de vérification envoyé à cet e-mail. La signature de la demande d’URL est req=login&action=verify.
  • Affichez un formulaire de connexion permettant à l’utilisateur de se connecter. La signature de la demande d’URL est req=login (par exemple, action est vide.)
  • Connectez-vous en vérifiant l’adresse e-mail (nom d’utilisateur) et le mot de passe. La signature de la demande d’URL est req=login&action=login.
  • Déconnexion à la demande de l’utilisateur. La signature de la demande d’URL est req=login&action=logout.
  • Page de destination de l’application. La signature de la demande d’URL est req=login&action=begin.
  • Si l’utilisateur est actuellement connecté, accédez à la page d’accueil de l’application.

Voir des exemples ci-dessous :

#include "vely.h"
#include "login.h"

// Handle session maintenance, login, logout, session verification
// for any multitenant Cloud application
void login () {
    // Get URL input parameter "action"
    input-param action

    // Get global request data, we record session information in it, so it's handy
    reqdata *rd;
    get-req data to rd

    // If session is already established, the only reason why we won't proceed to
    // application home is if we're logging out
    if (rd->is_logged_in) {
        if (strcmp(action, "logout")) {
            _show_home();
            exit-request
        }
    }

    // Application screen to get started. Show links to login or signup and show
    // home screen appropriate for this
    if (!strcmp (action, "begin")) {
        _show_home();
        exit-request

    // Start creating new user. Ask for email and password, then proceed to create user
    // when this form is submitted.
    } else if (!strcmp (action, "newuser")) {
        @Create New User<hr/>
        @<form action="https://opensource.com/?req=login" method="POST">
        @<input name="action" type="hidden" value="createuser">
        @<input name="email" type="text" value="" size="50" maxlength="50" required autofocus placeholder="Email">
        @<input name="pwd" type="password" value="" size="50" maxlength="50" required placeholder="Password">
        @<input type="submit" value="Sign Up">
        @</form>

    // Verify code sent to email by user. The code must match, thus verifying email address    
    } else if (!strcmp (action, "verify")) {
        input-param code
        input-param email
        // Get verify token based on email
        run-query @db_multitenant_SaaS = "select verify_token from users where email="%s"" output db_verify : email
            query-result db_verify to define db_verify
            // Compare token recorded in database with what user provided
            if (!strcmp (code, db_verify)) {
                @Your email has been verifed. Please <a href="https://opensource.com/?req=login">Login</a>.
                // If matches, update user info to indicate it's verified
                run-query @db_multitenant_SaaS no-loop = "update users set verified=1 where email="%s"" : email
                exit-request
            }
        end-query
        @Could not verify the code. Please try <a href="https://opensource.com/?req=login">again</a>.
        exit-request

    // Create user - this runs when user submits form with email and password to create a user    
    } else if (!strcmp (action, "createuser")) {
        input-param email
        input-param pwd
        // create hashed (one-way) password
        hash-string pwd to define hashed_pwd
        // generate random 5 digit string for verify code
        random-string to define verify length 5 number
        // create user: insert email, hashed password, verification token. Current verify status is 0, or not verified
        begin-transaction @db_multitenant_SaaS
        run-query @db_multitenant_SaaS no-loop = "insert into users (email, hashed_pwd, verified, verify_token, session) values ('%s', '%s', '0', '%s', '')" : email, hashed_pwd, verify affected-rows define arows error define err on-error-continue
        if (strcmp (err, "0") || arows != 1) {
            // if cannot add user, it probably doesn't exist. Either way, we can't proceed.
            login_or_signup();
            @User with this email already exists.
            rollback-transaction @db_multitenant_SaaS
        } else {
            // Create email with verification code and email it to user
            write-string define msg
                @From: vely@vely.dev
                @To: <<p-out email>>
                @Subject: verify your account
                @
                @Your verification code is: <<p-out verify>>
            end-write-string
            exec-program "/usr/sbin/sendmail" args "-i", "-t" input msg status define st
            if (st != 0) {
                @Could not send email to <<p-out email>>, code is <<p-out verify>>
                rollback-transaction @db_multitenant_SaaS
                exit-request
            }
            commit-transaction @db_multitenant_SaaS
            // Inform the user to go check email and enter verification code
            @Please check your email and enter verification code here:
            @<form action="https://opensource.com/?req=login" method="POST">
            @<input name="action" type="hidden" value="verify" size="50" maxlength="50">
            @<input name="email" type="hidden" value="<<p-out email>>">
            @<input name="code" type="text" value="" size="50" maxlength="50" required autofocus placeholder="Verification code">
            @<button type="submit">Verify</button>
            @</form>
        }

    // This runs when logged-in user logs out.    
    } else if (!strcmp (action, "logout")) {
        // Update user table to wipe out session, meaning no such user is logged in
        if (rd->is_logged_in) {
            run-query @db_multitenant_SaaS = "update users set session='' where userId='%s'" : rd->sess_userId no-loop affected-rows define arows
            if (arows == 1) {
                rd->is_logged_in = false; // indicate user not logged in
                @You have been logged out.<hr/>
            }
        }
        _show_home();

    // Login: this runs when user enters user name and password
    } else if (!strcmp (action, "login")) {
        input-param pwd
        input-param email
        // create one-way hash with the intention of comparing with user table - password is NEVER recorded
        hash-string pwd to define hashed_pwd
        // create random 30-long string for session ID
        random-string to rd->sess_id length 30
        // Check if user name and hashed password match
        run-query @db_multitenant_SaaS = "select userId from users where email="%s" and hashed_pwd='%s'" output sess_userId : email, hashed_pwd
            query-result sess_userId to rd->sess_userId
            // If match, update user table with session ID
            run-query @db_multitenant_SaaS no-loop = "update users set session='%s' where userId='%s'" : rd->sess_id, rd->sess_userId affected-rows define arows
            if (arows != 1) {
                @Could not create a session. Please try again. <<.login_or_signup();>> <hr/>
                exit-request
            }
            // Set user ID and session ID as cookies. User's browser will return those to us with every request
            set-cookie "sess_userId" = rd->sess_userId
            set-cookie "sess_id" = rd->sess_id
            // Display home, make sure session is correct first and set flags
            _check_session();
            _show_home();
            exit-request
        end-query
        @Email or password are not correct. <<.login_or_signup();>><hr/>

    // Login screen, asks user to enter user name and password    
    } else if (!strcmp (action, "")) {
        login_or_signup();
        @Please Login:<hr/>
        @<form action="https://opensource.com/?req=login" method="POST">
        @<input name="action" type="hidden" value="login" size="50" maxlength="50">
        @<input name="email" type="text" value="" size="50" maxlength="50" required autofocus placeholder="Email">
        @<input name="pwd" type="password" value="" size="50" maxlength="50" required placeholder="Password">
        @<button type="submit">Go</button>
        @</form>
    }
}

// Display Login or Sign Up links
void login_or_signup() {
        @<a href="https://opensource.com/?req=login">Login</a> & & <a href="https://opensource.com/?req=login&action=newuser">Sign Up</a><hr/>
}

Application à usage général (_show_home.vely)

Avec ce didacticiel, vous pouvez créer n’importe quelle application SaaS mutualisée de votre choix. Le module de traitement mutualisé ci-dessus (login.vely) appelle le _show_home() fonction, qui peut héberger n’importe quel code de la vôtre. Cet exemple de code montre l’application Notes, mais cela pourrait être n’importe quoi. La _show_home() La fonction appelle le code que vous souhaitez et est un plug-in d’application multi-locataire à usage général :

#include "vely.h"

void _show_home() {
    notes();
    exit-request
}

Application Notes (notes.vely)

L’application est capable d’ajouter, de lister et de supprimer n’importe quelle note :

#include "vely.h"
#include "login.h"

// Notes application in a multitenant Cloud
void notes () {
    // get global request data
    reqdata *rd;
    get-req data to rd
    // If session invalid, display Login or Signup
    if (!rd->is_logged_in) {
        login_or_signup();
    }
    // Greet the user
    @<h1>Welcome to Notes!</h1><hr/>
    // If not logged in, exit - this ensures security verification of user's identity
    if (!rd->is_logged_in) {
        exit-request
    }
    // Get URL parameter that tells Notes what to do
    input-param subreq
    // Display actions that Notes can do (add or list notes)
    @<a href="https://opensource.com/?req=notes&subreq=add">Add Note</a> <a href="https://opensource.com/?req=notes&subreq=list">List Notes</a><hr/>

    // List all notes for this user
    if (!strcmp (subreq, "list")) {
        // select notes for this user ONLY
        run-query @db_multitenant_SaaS = "select dateOf, note, noteId from notes where userId='%s' order by dateOf desc" : rd->sess_userId output dateOf, note, noteId
            query-result dateOf to define dateOf
            query-result note to define note
            query-result noteId to define noteId
            // change new lines to <br/> with fast cached Regex
            match-regex "\n" in note replace-with "<br/>\n" result define with_breaks status define st cache
            if (st == 0) with_breaks = note; // nothing was found/replaced, just use original
            // Display a note
            @Date: <<p-out dateOf>> (<a href="https://opensource.com/?req=notes&subreq=delete_note_ask&note_id=%3C%3Cp-out%20noteId%3E%3E">delete note</a>)<br/>
            @Note: <<p-out with_breaks>><br/>
            @<hr/>
        end-query
    }

    // Ask to delete a note
    else if (!strcmp (subreq, "delete_note_ask")) {
        input-param note_id
        @Are you sure you want to delete a note? Use Back button to go back, or <a href="https://opensource.com/?req=notes&subreq=delete_note&note_id=%3C%3Cp-out%20note_id%3E%3E">delete note now</a>.
    }

    // Delete a note
    else if (!strcmp (subreq, "delete_note")) {
        input-param note_id
        // Delete note
        run-query @db_multitenant_SaaS = "delete from notes where noteId='%s' and userId='%s'" : note_id, rd->sess_userId affected-rows define arows no-loop error define errnote
        // Inform user of status
        if (arows == 1) {
            @Note deleted
        } else {
            @Could not delete note (<<p-out errnote>>)
        }
    }

    // Add a note
    else if (!strcmp (subreq, "add_note")) {
        // Get URL POST data from note form
        input-param note
        // Insert note under this user's ID
        run-query @db_multitenant_SaaS = "insert into notes (dateOf, userId, note) values (now(), '%s', '%s')" : rd->sess_userId, note affected-rows define arows no-loop error define errnote
        // Inform user of status
        if (arows == 1) {
            @Note added
        } else {
            @Could not add note (<<p-out errnote>>)
        }
    }

    // Display an HTML form to collect a note, and send it back here (with subreq="add_note" URL param)
    else if (!strcmp (subreq, "add")) {
        @Add New Note
        @<form action="https://opensource.com/?req=notes" method="POST">
        @<input name="subreq" type="hidden" value="add_note">
        @<textarea name="note" rows="5" cols="50" required autofocus placeholder="Enter Note"></textarea>
        @<button type="submit">Create</button>
        @</form>
    }
}

SaaS avec performances C

Vely permet d’exploiter la puissance du C dans vos applications Web. Une application SaaS mutualisée est un excellent exemple de cas d’utilisation qui en bénéficie. Jetez un œil aux exemples de code, écrivez du code et essayez Vely.

Source

Quitter la version mobile