_       _       
  (_) ___ | |_ ____
  | |/ _ \| __|_  /
  | | (_) | |_ / / 
 _/ |\___/ \__/___|

How to build Jotz CMS from scratch

Directory structure


Upload using scp

To upload complete directory to web server:

scp -r test/ jotzae@www556.your-server.de:/public_html/tedz.eu/ 

Addon domain, DNS, etc.

Enabling https on addon domain

  echo "Hello.";

PHP script directory: jotz_cms

echo "This is test.php\n";

I pointed the browser to "https://robosumo.eu/jotz/test.php" to verify that I could see the expected output of the PHP script, as shown below:

This is test.php

Most of the files in the "jotz" folder are not intended to be accessed directly, but rather to be targets for symlinks in each user's "cms" subdirectory. So, to prevent visitors from accessing the contents of this folder directly, I created a file "/public_html/robosumo.eu/jotz/.htaccess" containing the following:

order deny,allow
deny from all

I pointed the browser to "https://robosumo.eu/jotz/test.php" again to verify that the file was no longer accessible.

Then, I changed the ".htaccess" file so that the admin can run PHP scripts from that folder (e.g. "create_user.php"). This was the new "/public_html/robosumo.eu/jotz/.htaccess":

AuthType Basic
AuthName "jotz"
AuthBasicProvider file
AuthUserFile "/usr/www/users/jotzae/robosumo.eu/jotz/.htpasswd"
Require user tedz

I created a file ".htpasswd" on my local machine, as follows:

touch .htpasswd 
htpasswd -b .htpasswd tedz mypassw0rd

Then, I uploaded that ".htpasswd" file to "/public_html/robosumo.eu/jotz/.htpasswd" using FileZilla.

Test user directory

I don't seem to have SSH access to the web server, which complicates the creation of symlinks in each user's folder, so I'm using the PHP's exec function to create them.

To create a symlink to "/public_html/jotz/test.php" in the directory "/public_html/d12345678/", I created a file "/public_html/d12345678/links.php" containing the following:

exec('ln -s ../jotz/test.php test.php');

When I point the browser to "https://robosumo.eu/d12345678/links.php" it displays an empty page, but the symlink "test.php" is created in the "d12345678" folder. To verify that the symlink is working correctly, I pointed the browser to "https://robosumo.eu/d12345678/test.php" and the expected output of the PHP script "test.php" was displayed, as shown below:

This is test.php

I then deleted "links.php" using FileZilla.

AuthType Basic
AuthName "jotz"
AuthBasicProvider file
AuthUserFile "/usr/www/users/jotzae/robosumo.eu/jotz/.htpasswd"
Require user d12345678

Create a new user

To create a new users d12345678 and d12341234, browse to the following two URLs:


Note that passwords for the above users must be added to /public_html/robosumo.eu/jotz/.htpasswd

To do this, I regenerated the file on my local computer (as shown below) and then uploaded it to the web server.

touch .htpasswd 
htpasswd -b .htpasswd tedz mypassw0rd
htpasswd -b .htpasswd d12345678 p4ssw0rd
htpasswd -b .htpasswd d12341234 pa55word

In principle, the users could probably be added to the ".htpasswd" file by a PHP script (e.g. by "newuser.php") on the server, but I didn't pursue that. Also, the ".htpasswd" file could be downloaded, have new user(s) added, and then be re-uploaded to the web server. Since I will be generating all user accounts as a batch, it's basically easiest to just generate the entire ".htpasswd" file locally and then upload.

Create user from terminal using wget

A new user can be created on the online Jotz installation from a terminal on a local machine using wget:

wget --user=tedz --password=PASSWORD -O created12341234.html https://robosumo.eu/jotz/newuser.php?username=d12341234

To run the cleaner script, which deletes both test user folders (d12345678 and d12341234), and pipe the output to stdout:

wget --user=tedz --password=PASSWORD -O - https://robosumo.eu/jotz/clean.php 

Delete test users from the CMS

Browse to this URL to delete users d12345678 and d12341234 from the CMS:


Generating a list of random passwords

// Generate 8-character passwords for robosumo.eu users
// Each character is either a digit or a lower case letter
// Written by Ted Burke - last updated 11-Nov-2022
// To compile:
//    gcc -o generate_passwords generate_passwords.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
    int m, n;
    char c;

    time_t t;
    srand((unsigned) time(&t));

    for (m=0 ; m<100 ; ++m)
        for (n=0 ; n<8 ; ++n)
            c = rand() % 36;
            if (c < 10) c += '0';
            else c += 'a' - 10;
            printf("%c", c);

    return 0;

Extract first names from a list of full names

Given a list of names (names.txt) like this..

Smith, John
Doe, Jane
Kelly, Pat M.

...extract this:


This is the command I used:

cat names.txt | sed 's/[^,]*,[[:space:]]*\([A-Za-z]*\).*$/\1/g'

Create user accounts

Given a file "logins.csv" containing list of user login details in the following format...

Group,Index,Student No.,Name,First name,Email Address,Password
D1,1,D12345678,"Smith, John.",John,D12345678@mytudublin.ie,h6ds4f44
D1,2,D12341234,"Doe, Jane, S.",Jane,D12341234@mytudublin.ie,lnhgz0i9

Create user accounts on robosumo.eu using the following script:

import csv, os

adminusername = "dave"
adminpassword = "P4SSWORD"

# Create new password file and add admin's password
os.system('rm robosumo.eu.htpasswd')
os.system('touch robosumo.eu.htpasswd')
os.system(f'htpasswd -b robosumo.eu.htpasswd {adminusername} {adminpassword}')

# Read users from CSV file, create their accounts and add their passwords to the password file
with open("logins.csv") as file:
    reader = csv.reader(file)
    next(reader)  # add this to skip the header row
    for group, number, username, fullname, firstname, email, password in reader:
        # Create user by accessing newuser.php on the web server
        os.system(f'wget --user={adminusername} --password={adminpassword} -O - https://robosumo.eu/jotz/newuser.php?username={username}')

        # Add password to local file robosumo.eu.htpasswd for uploading as .htpasswd
        os.system(f'htpasswd -b robosumo.eu.htpasswd {username} {password}')

        print(f'Created user {username} with password {password}')

Email login details to users

The Python script below is based on an example from https://mailtrap.io/blog/python-mail-merge/


To send a bespoke email to each user with their login details:

import csv, smtplib

message = """Subject: Jotz CMS login details for your account on robosumo.eu
To: {recipient}
From: accounts@robosumo.eu

Hi {firstname},

Your Jotz CMS login details for robosumo.eu are:

username: {username}
password: {password}
blog address: https://robosumo.eu/{username}

Ted """

smtp_server = "mail.your-server.de"
port = 587 # port number for TLS connection to SMTP
login = "accounts@robosumo.eu"
password = "P4SSWORD"

with smtplib.SMTP(smtp_server, port) as server:
    server.login(login, password)

    with open("logins.csv") as file:
        reader = csv.reader(file)
        next(reader)  # add this to skip the header row
        for group, number, username, fullname, firstname, email, password in reader:
                message.format(recipient=email, firstname=firstname, username=username, password=password)
            print(f'Sent to {fullname}')


  1. Add some analytics
  2. Custom upload file size limit for lecturers
  3. Backup feature for users to download a zip file of their markdown files, uploads, custom CSS/header/footer
  4. Add explanatory text to text input fields in settings page
  5. Reduce default height of text input fields in settings page
  6. Adjust height of text edit box on edit.php page to keep entire default text box on screen
  7. Add some kind of page view count / logging to each page?
  8. Make URLs case insensitive, e.g. https://robosumo.eu/d12345678
  9. Add #tags to article metadata - i.e. new text field in edit.php, store tags in *.md, display tags in e.g. view.php
  10. Add Tools page: image cleaner, form to submit laser cutting patterns, etc.
  11. Adjust editor text box so that it fits entirely on screen by default.
  12. Adjust font size in editor text box for mobile version.
  13. Add URL parameter for edit.php to scroll editor text box to same line as before you clicked "Create / update article".
  14. Change text on "Create / update article" button so that it says either "Create article" or "Update article".
  15. Modify newuser.php so that each user's custom .htaccess generates the path to the .htpasswd from the current location rather than current hardcoded reference to robosumo.eu.