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.
Contents
- Utilisation de Vely pour le SaaS
- Configurer l’application
- Configurer la base de données
- Connecter Vely à une base de données
- Construire l’application
- Démarrer le serveur d’applications
- Configurer le serveur Web
- Configurer la messagerie locale
- Accéder au serveur d’application depuis le navigateur
- Code source
- SaaS avec performances C
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_SaaS
mais 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_SaaS
proprié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
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@localhost
vous pouvez alors vérifier que l’e-mail a bien été envoyé en consultant /var/mail/
(le « spool de courrier »).
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_LOGINtypedef 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.vely
et 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¬e_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¬e_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.