Open-source News

More Development Activity Ticking Up Around Vulkan For Blender

Phoronix - Mon, 11/07/2022 - 22:00
There has long been plans for supporting the Vulkan API with the Blender 3D modelling open-source software but there has been a lack of developers working on it. Fortunately, things are starting to (slowly) come together on Vulkan enablement for Blender...

Some AMD RDNA3 Fixes Land In Mesa Git Ahead Of December's Radeon RX 7900 Series Launch

Phoronix - Mon, 11/07/2022 - 19:55
With the AMD Radeon RX 7900 XT / RX 7900 XTX having been announced last week and set to ship on 13 December, it's down to crunch time for ensuring that the open-source Linux driver support is in shape. Unlike on the Windows side where it's just expected of the user to navigate to AMD.com and download a convenient driver installer, on Linux that's not exactly the case. AMD will likely have their Radeon Software for Linux driver package on their website but that is limited in scope to their few supported enterprise/LTS Linux distributions supported, while most gamers/enthusiasts will be left wondering about the Linux kernel and Mesa versioning requirements...

The Linux Kernel Has Been Forcing Different Behavior For Processes Starting With "X"

Phoronix - Mon, 11/07/2022 - 18:56
An ugly hack within the Linux kernel that has been in mainline for over three years has been called out. Due to a buggy X.Org Server / xf86-video-modesetting DDX, the Linux kernel has been imposing different behavior on whether a process starts with "X" and in turn disable the atomic mode-setting support...

Intel Preparing HDMI 2.1 FRL For Their Linux Driver, Native HDMI 2.1 For Meteor Lake

Phoronix - Mon, 11/07/2022 - 18:38
With next-generation Meteor Lake CPUs the integrated graphics are set to have native HDMI 2.1 display capabilities. Intel's open-source Linux kernel driver has begun those HDMI 2.1 preparations and sent out today were early patches for enabling HDMI 2.1 Fixed Rate Link (FRL)...

Intel RAO-INT Added To GCC 13, Grand Ridge & Granite Rapids CPU Targets Ready

Phoronix - Mon, 11/07/2022 - 18:23
Intel compiler engineers continue being very busy working to land as much of the new CPU feature support as they can into GCC 13 for what is the next annual compiler release that will debut as GCC 13.1 in the early months of 2023...

Meson 0.64 Build System Released With Intel oneAPI Compiler Support, Incremental ThinLTO

Phoronix - Mon, 11/07/2022 - 18:03
Debuting on Sunday was Meson 0.64 as the newest version of this open-source build system that is increasingly being used by a variety of software projects for its speed, good cross-platform support, and overall feature set compared to alternatives...

What you actually need to know about open source to get started

opensource.com - Mon, 11/07/2022 - 16:00
What you actually need to know about open source to get started Katie Edwards Mon, 11/07/2022 - 03:00

So you want (or need) to figure out what "open source" really means. I'll cover the basics of open source, whether you're interested in contributing to a project or want to be in the loop at a new job where the term keeps getting thrown around.

Full disclosure: I am a person with little technical experience, working in the content-design fringes of a very technical open source environment. Given my background in marketing and communication, I felt like a fish out of water when I made this career switch. Git, data science, the ins and outs of software… It was, and still is a year later, a lot to comprehend.

But that's why I'm writing this piece. I want to help make open source a little less intimidating. After all, at the center of open source is a supportive learning community—built for everyone, technically experienced or not.

I'll start with the absolute basics.

What is open source?

For the record, the industry definition of open source is available at the Open Source Initiative site.

However, the popular perception of "open source" software is usually that it doesn't cost anything, the source code is accessible, anyone can contribute to it, and you can redistribute it or do whatever else you want with it.

Some of that is true, and some of it plays into a few common misconceptions, one of which is cost.

More great content Free online course: RHEL technical overview Learn advanced Linux commands Download cheat sheets Find an open source alternative Explore open source resources Open source costs $0

Is it true? Usually, but not always. By nature of its code being publicly available, open source software can be obtained at no cost. However, for-profit companies do exist around open source projects. But if the software is available at no cost, how do open source companies even exist? How do they make money?

The concept of having a "free product" is counter-intuitive. But that's just the thing: A company doesn't have to sell software to profit from the management of products, storage of data, and customer support.

Many companies follow a subscription model, offering customer support in case of bugs or general confusion. Data storage isn't free, so that is another area where these companies can bring in income. In this regard, the "product" isn't the software; it's the benefit of a subscription.

  1. The source code is accessible: Is it true? Yes, always. This accessibility is a prerequisite for adopting the term "open source." The source code must be available to view, use, modify, and redistribute.
  2. You can do whatever you want with the code: Is it true? It depends. Subject to licensing terms, there are some limitations on how you can use code, but you can generally use it however you'd like. Whether that means tweaking a project to fit a specific need or using it as the basis for something else, open source software is yours, and everyone else's, to modify.
  3. Anyone can contribute to open source projects: Is it true? Yes - within limits. Anyone with the right skill set can contribute to open source. However, that doesn't mean all contributions are always accepted and implemented.

For example, say you're interested in a project where the end goal is a catalog of all the types of birds in the world. You're really into dinosaurs, specifically dinosaurs that may have eventually evolved into modern-day birds. So, you contribute entries for all of the most bird-like dinosaurs. The project owners could see this and think, "Sweet, those are some great prehistoric birds." However, they're also allowed to say, "Hmm, those dinosaurs are like birds, but they're technically not birds yet. They probably don't belong on Birdpedia."

Luckily, projects don't usually work under lawless conditions. Open source projects typically come with contribution guidelines and codes of conduct, so you don't have to worry about your additions flying off the rails.

Why open source?

So, after all the contributions are made (if it's ever actually done), why would people give away their software for no cost? If so many people put their time and effort into creating something, why wouldn't they band together and slap a price tag on it?

This question comes with a lot of answers. Here are a few:

  1. Starting a business is hard, especially if the project you're working on doesn't form the strong foundation for a money machine. It can be easier to rally a bunch of like-minded people without commitments or the expectation of paychecks.
  2. Most open source communities consist of people interested in improving software or bringing it into existence but don't have the time or interest to commit to working full-time on a project. Sometimes open source represents passion projects, geek groups, and crowd-sourced solutions to annoying problems.
  3. The groups that form around open source projects of all sizes foster supportive communities where contributors and onlookers alike can practice their skills, improve software they regularly use, teach and learn from each other, and feel empowered to make their voices heard. Many open source communities are essentially hyper-focused online hobby clubs.
Where do I get involved?

Now you may ask yourself, "But what do I do with this information? Can I contribute to open source projects? What if I'm not good enough yet?"

Never fear—even beginners are welcome to contribute to open source projects. It's a great way to hone your skills while working with a community towards a larger goal. And, as I talked about earlier, the worst that can happen is your changes aren't merged into Birdpedia (and that's because those product owners just can't see your vision of a Birdpedia where birds and their ancestors gleefully coexist in an online world of bird-related knowledge).

[ Related read Why do we contribute to open source software? ]

Do you have to know how to code to contribute to projects? Contrary to popular belief, no, you don't. Projects "take a village" to thrive, which means they need input from people of all different backgrounds. Visual designers, writers, marketers, reviewers, translators, subject matter enthusiasts, and even just users of the resulting product are all valuable contributors. Not only do they help build out and improve products, but they identify bugs, suggest improvements, spread the word about the project, and generally strengthen the community.

In short, no matter what your background or experience, if you're interested in open source or a specific project, you're nearly guaranteed to be welcomed with open arms.

Get started with open source now

Still not sure where to begin? Here are some ideas and resources to get you started:

  • Up For Grabs is a "list of open source projects which have curated tasks specifically for new contributors." This is a great place to find an easy first PR opportunity, which is a great way to find out what kind of contributions you'll enjoy.
  • Check out this list of beginner-friendly projects on GitHub.
  • If you're still not feeling inspired, consider contributing to (or flying with) PatternFly, Red Hat's open design system.

A beginner's guide to open source explained in plain terms.

Image by:

Opensource.com

What to read next This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License. Register or Login to post a comment.

Build your own SaaS on Linux with Vely

opensource.com - Mon, 11/07/2022 - 16:00
Build your own SaaS on Linux with Vely Sergio Mijatovic Mon, 11/07/2022 - 03:00

Vely combines high performance and the low footprint of C with the ease of use and improved safety of languages like PHP. It's free and open source software, licensed under GPLv3 and LGPL 3 for libraries, so you can even build commercial software with it.

Using Vely for SaaS

You can use Vely to create a multitenant web application that you can run on the Internet as Software-as-a-Service (SaaS). Each user has a completely separate data space from any other.

In this example web application, a user can sign up for a notebook service to create notes and then view and delete them. It demonstrates several technology integrations in just 310 lines of code across seven source files. The technologies include:

  • MariaDB
  • Web browser
  • Apache
  • Unix sockets
How it works

Here's how the application works from a user's perspective. A code walk-through follows the images.

The app allows a user to create a new login by specifying an email address and password. You can style these any way you like, such as with CSS:

Image by:

(Sergio Mijatovic, CC BY-SA 4.0)

Verify the user's email:

Image by:

(Sergio Mijatovic, CC BY-SA 4.0)

Each user logs in with their unique username and password:

Image by:

(Sergio Mijatovic, CC BY-SA 4.0)

Once logged in, a user can add a note:

Image by:

(Sergio Mijatovic, CC BY-SA 4.0)

A user can get a list of notes:

Image by:

(Sergio Mijatovic, CC BY-SA 4.0)

The app asks for confirmation before deleting a note:

Image by:

(Sergio Mijatovic, CC BY-SA 4.0)

After the user confirms, the note is deleted:

Image by:

(Sergio Mijatovic, CC BY-SA 4.0)

Setup prerequisites

Follow the installation instructions on Vely.dev. It's a quick process that uses standard packaging tools, such as DNF, APT, Pacman, or Zypper.

Because they are part of this example, you must install Apache as a web server and MariaDB as a database.

After installing Vely, turn on syntax highlighting in Vim if you're using it:

vv -mGet the source code

The source code for this demonstration SaaS app is part of the Vely installation. It's a good idea to create a separate source code directory for each application (and you can name it whatever you like). In this case, unpacking the source code does that for you:

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

By default, the application is named multitenant_SaaS, but you can call it anything (if you do that, change it everywhere).

Set up the application

The very first step is to create an application. It's simple to do with Vely's vf utility:

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

This command creates a new application home (/var/lib/vv/multitenant_SaaS) and performs the application setup for you. Mostly, that means creating various subdirectories in the home folder and assigning privileges. In this case, only the current user (the result of whoami) owns the directories, with 0700 privileges, which ensures that no one else has access to the files.

Set up the database

Before doing any coding, you need a place to store the information used by the application. First, create a MariaDB database called db_multitenant_SaaS, owned by the user vely with password your_password. You can change any of these values, but remember to change them everywhere during this example.

Logged in as root in the MySQL utility:

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;

Then create database objects (tables and records and so on) in the database:

USE db_multitenant_SaaS;
SOURCE setup.sql;
exitConnect Vely to a database

To let Vely know where your database is and how to log into it, create a database config file named db_multitenant_SaaS. (This is the name used by the database statements in the source code, so if you change it, make sure you change it everywhere.)

Vely uses native MariaDB database connectivity, so you can specify any options that a given database lets you:

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

Use the vv utility to make the application, using the --db option to specify the MariaDB database and the database config file:

$ vv -q --db=mariadb:db_multitenant_SaaS

Programming and development Red Hat Developers Blog Programming cheat sheets Try for free: Red Hat Learning Subscription eBook: An introduction to programming with Bash Bash shell scripting cheat sheet eBook: Modernizing Enterprise Java An open source developer's guide to building applications Start the application server

To start the application server for your web application, use the vf FastCGI process manager. The application server uses a Unix socket to communicate with the web server (creating a reverse proxy):

$ vf -w 3 multitenant_SaaS

This starts three daemon processes to serve the incoming requests. You can also start an adaptive server that increases the number of processes to serve more requests and gradually reduce the number of processes when they're not needed:

$ vf multitenant_SaaS

See vf for more options to help you achieve the best performance.

When you need to stop your application server, use the -m quit option:

$ vf -m quit multitenant_SaaSSet up the web server

This is a web application, so the application needs a web server. This example uses Apache by way of a Unix socket listener.

1. Set up Apache

To configure Apache as a reverse proxy and connect your application to it, you need to enable FastCGI proxy support, which generally means using the proxy and proxy_fcgi modules.

For Fedora systems (or others, like Arch) enable the proxy and proxy_fcgi modules by adding (or uncommenting) the appropriate LoadModule directives in the /etc/httpd/conf/httpd.conf Apache configuration file.

For Debian, Ubuntu, and similar systems, enable the proxy and proxy_fcgi modules:

$ sudo a2enmod proxy
$ sudo a2enmod proxy_fcgi

For OpenSUSE, add these lines to the end of /etc/apache2/httpd.conf:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so2. Configure Apache

Now you must add the proxy information to the Apache configuration file:

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

The location of your configuration may vary, depending on your Linux distribution:

  • Fedora, CentOS, Mageia, and Arch: /etc/httpd/conf/httpd.conf
  • Debian, Ubuntu, Mint: /etc/apache2/apache2.conf
  • OpenSUSE: /etc/apache2/httpd.conf
3. Restart

Finally, restart Apache. On Fedora and similar systems, as well as Arch Linux:

$ sudo systemctl restart httpd

On Debian and Debian-based systems, as well as OpenSUSE:

$ sudo systemctl restart apache2Set up local mail

This example uses email as a part of its function. If your server can already send email, you can skip this. Otherwise, you can use local mail (myuser@localhost) just to test it out. To do that, install Sendmail.

On Fedora and similar:

$ sudo dnf install sendmail
$ sudo systemctl start sendmail

On Debian systems (like Ubuntu):

$ sudo apt install sendmail
$ sudo systemctl start sendmail

When the application sends an email to a local user, such as OS_user@localhost, then you can verify that the email was sent by looking at /var/mail/ (the "mail spool").

Access the application server from the browser

Assuming you're running the application locally, use http://127.0.0.1/multitenant_SaaS?req=notes&action=begin to access your application server from your web browser. If you're running this on a live server on the Internet, you may need to adjust your firewall settings to allow HTTP traffic.

Source code

This example application contains seven source files. You can review the code yourself (remember, it's just 310 lines across these files), but here's an overview of each one.

SQL setup (setup.sql)

The two tables created are:

  • users: Information about each user. Each user in the users table has its own unique ID (userId column) along with other information such as email address and whether it's verified. There's also a hashed password. An actual password is never stored in plain text (or otherwise); a one-way hash is used to check the password.
  • notes: Notes entered by the user. The notes table contains the notes, each along with userId column that states which user owns them. The userId column's value matches the namesake column from users table. This way, every note clearly belongs to a single user.

The file contents:

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);Run-time data (login.h)

To properly display the Login, Sign Up, and Logout links, you need some flags that are available anywhere in the application. Also, the application uses cookies to maintain a session, so this needs to be available anywhere, for example, to verify that the session is valid. Every request sent to the application is confirmed that way. Only requests that come with verifiable cookies are permitted.

So to that effect, you have a global_request_data type reqdata (request data) and in it there's sess_userId (ID of user) and sess_id (user's current session ID). You also have rather self-explanatory flags that help render 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 ();

#endifSession checking and session data (_before.vely)

Vely has a notion of a before_request_handler. The code you write executes before any other code that handles a request. To do this, all you need is to write this code in a file named _before.vely, and the rest is automatically handled.

Anything that a SaaS application does, such as handling requests sent to an application, must be validated for security. This way, the application knows whether the caller has the permissions needed to perform an action.

Checking for permission is done here in a before-request handler. That way, whatever other code you have handling a request, you already have the session information.

To keep session data (like session ID and user ID) available anywhere in your code, you use global_request_data. It's just a generic pointer (void*) to memory that any code that handles requests can access. This is perfect for handling sessions, as shown below:

#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 ();
}Checking if the session is valid (_check_session.vely)

One of the most important tasks in a multitenant SaaS application is to check (as soon as possible) if the session is valid by checking whether a user is logged in. It's done by getting the session ID and user ID cookies from the client (such as a web browser) and checking these against the database where sessions are stored:

#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;
    }
}Signing up, Logging in, Logging out (login.vely)

The basis of any multitenant system is the ability for a user to sign up, log in, and log out. Typically, signing up involves verifying the email address; more often than not, the same email address is used as a username. That's the case here.

There are several subrequests implemented here that are necessary to perform the functionality:

  • When Signing Up a new user, display the HTML form to collect the information. The URL request signature for this is req=login&action=newuser.
  • As a response to the Sign Up form, create a new user. The URL request signature is req=login&action=createuser. The input-param signal obtains an email and pwd POST form fields. The password value is a one-way hash, and an email verification token is created as a random five-digit number. These are inserted into the users table, creating a new user. A verification email is sent, and the user is prompted to read the email and enter the code.
  • Verify the email by entering the verification code sent to that email. The URL request signature is req=login&action=verify.
  • Display a Login form for the user to log in. The URL request signature is req=login (for instance, action is empty.)
  • Log in by verifying the email address (username) and password. The URL request signature is req=login&action=login.
  • Logout at the user's request. The URL request signature is req=login&action=logout.
  • Landing page for the application. The URL request signature is req=login&action=begin.
  • If the user is currently logged in, go to the application's landing page.

See examples of these below:

#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/>
}General-purpose application (_show_home.vely)

With this tutorial, you can create any multitenant SaaS application you want. The multitenant-processing module above (login.vely) calls the _show_home() function, which can house any code of yours. This example code shows the Notes application, but it could be anything. The _show_home() function calls any code you wish and is a general-purpose multitenant application plug-in:

#include "vely.h"

void _show_home() {
    notes();
    exit-request
}Notes application (notes.vely)

The application is able to add, list, and delete any given 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 with C performance

Vely makes it possible to leverage the power of C in your web applications. A multitenant SaaS application is a prime example of a use case that benefits from that. Take a look at the code examples, write some code, and give Vely a try.

Vely makes it possible to leverage the power of C in your web applications.

Image by:

Opensource.com

Databases Programming Linux What to read next This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License. Register or Login to post a comment.

Pages