Juju is a cloud-based Content Management System and Database-as-a-Service. The Juju platform allows for fine-grained control over the design and content of web pages served from the infrastructure. In addition, the media CDN and database service provides the ability to add dynamic, database-driven content to any page in both pre and post-rendered models.
An overview of the changes to the Juju platform over the last 12 months.
Juju is a highly secure system. All API and dashboard data are encrypted in transit using secure sockets (SSL, or more accurately, TLS). All data is also encrypted at rest, both in our database and in our blob storage systems. Our systems are hardended against DOS attacks, and are constantly monitored to ensure system health.
Our data-centers for front-end request serving and database are located in the central US and western US. We also have a pair of data-centers in Europe for customers needing that capability. In addition to our data-centers, we maintain a world-wide network of 35 edge-nodes that comprise our Content Delivery Network.
Yes, the Database API fully supports both filtering and searching. See the full-text search section in the documentation.
Sites do not have a limit on the number of pages.
The Juju CMS supports the concept of HTML templates and pages. Templates contain common HTML headers and footers and define "blocks" that can be overwritten at the page level.
Do create a template, select the "Templates" tab and click "New Template". A template needs a unique name among the other templates on the site.
A template can be as simple as:
<html>
<head>
<title>Title of the Page</title>
</head>
<body>
[[ block content ]]
[[ endblock ]]
</body>
</html>
To utilize media in a template, call the media
command with the name of the media
file you wish to include.
Example:
<img src="(( media('bestfile.jpg') ))">
The appropriate CDN URL of the media file will be inserted into the template.
To utilize a theme in a template, call the theme
command with the name of the theme
you wish to include.
Example:
<link href="(( theme('Main Theme') ))" rel="stylesheet">
The appropriate CDN URL of the compiled CSS theme will be inserted into the template.
To utilize a Javascript compontent in a template, call the js
command with the name of the component you wish to include.
Example:
<script src="(( js('My Component') ))"></script>
The appropriate CDN URL of the compiled component Javascript will be inserted into the template.
A page is the central piece of the CMS system. A page associates a template, a path (or route),
and blocks.
Once template exists in the system, it can be assigned to a page.
Blocks can be either WYSIWYG or "code". This allows for direct HTML editing or more visually based editing.
A theme is a collection of files that compile to a single CSS file that is located on a Global CDN.
To create a theme, click on the "Themes" tab and click "New Theme". A theme can be SASS, LESS, or plain CSS-based. A theme can consist of any number of files.
To publish a staging copy of a theme, save any file in the theme.
To publish a production compilation of the theme, click the "Publish Site" button at the top of the screen.
To utilize media in a theme, call the media
command with the name of the media
file you wish to include.
Example:
<img src="(( media('bestfile.jpg') ))">
The appropriate CDN URL of the media file will be inserted into the theme file.
A theme is a collection of files that compile to a single Javascript file that is located on a Global CDN.
To create a component, click on the "Components" tab and click "New Component". A component can consist of Javascript and HTML files.
To publish a staging copy of a component, click on the component name and click "Deploy Staging".
To publish a production compilation of the component, click the "Publish Site" button at the top of the screen or click "Deploy Production" from the component information page.
All media uploaded to the Juju platform is served from a global CDN for fast access.
To create a new database table, select the "Database" tab and click "Add Table".
Select a name for the table using uppercase, lowercase, and numeric characters only. A database table must have fields associated with it. Fields can be of many types including:
To create a new row for a table first select the table, then click "Create New [Table Name]". You can then enter in the fields for the new database row and click "Add Row".
To search a database, click into the search box on the selected table and type a query.
The query can be a fulltext query or inequality:
Mailchimp support is integrated via the "MailChimp Form" component.
The Juju platform is built oppon a RESTful API for access and manipulation of pages, themes, components, media, and database. API access is granted through the API keys in each project settings tab.
To authorize with the API, user either your API Key or Master Key to authenticate requests.
User the standard Authorization
header in the following way:
Authorization: Juju <key>
The database API provides access to the Juju DAAS.
Create a new database table with the following payload parameters:
{
"name":"NameOfTable",
"fields":[
{"field_type":"field_name"}
]
}
List tables in the site.
Manipulate a table in place or get details.
Create a new row in the table.
{
"field_string":"This field.",
"field_int":1234",
"field_float_":3.14
}
Creating a new record and return a new auto-increment ID.
Query the table for rows:
Update the table details.
Manipulate a table in place or get details.
Get the table row.
Update the table row.
Delete the table row.
Many apps have a unified login that works across the mobile app and other systems. Accessing user accounts through the REST API lets you build this functionality on top of Juju.
In general, users have the same features as other objects, such as the flexible schema via the meta_data field. The differences are that user objects must have a username and password, the password is automatically encrypted and stored securely, and Juju enforces the uniqueness of the username field.
Signing up a new user differs from creating a generic database object in that the username and password fields are required. The password field is handled differently than the others; it is encrypted when stored in the Juju system and never returned to any client request.
To sign up a new user, send a POST request to the users root. You may add any additional fields. For example, to create a user with a specific phone number:
curl -X POST \
-H "Authorization: Juju ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{"username":"skywalker","password":"asdfasdfasd", "email":"jo@funsite.com"}' \
https://${SITE_ID}.juju.io/api/v1/users
When the creation is successful, the HTTP response is a 201 Created.
The response body is a JSON object containing the id, the created_at timestamp of the newly-created object, and the session_token which can be used to authenticate subsequent requests as this user:
{
"created_at": "2011-11-07T20:58:34.448Z",
"username":"skywalker",
"email":"jo@funsite.com",
"id": 12341234123412,
"session_token": "pnktnjyb996sj4p156gjtp4im"
}
Do associate arbitrary meta-data with a user, create or update the user with a JSON structured called meta_data.
curl -X POST \
-H "Authorization: Juju ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{"username":"skywalker","password":"asdfasdfasd", "email":"jo@funsite.com", "meta_data":{"age":21}}' \
https://${SITE_ID}.juju.io/api/v1/users
The resulting response will refect the meta-data:
{
"created_at": "2011-11-07T20:58:34.448Z",
"username":"skywalker",
"email":"jo@funsite.com",
"meta_data": {
"age":21
},
"id": 12341234123412
}
Users can be queried by meta-data fields.
After you allow users to sign up, you need to let them log in to their account with a username and password in the future. To do this, send a POST request to the /api/v1/login endpoint with username and password as URL-encoded parameters:
curl -X GET \
-H "Authorization: Juju ${API_KEY}" \
-G \
--data-urlencode 'username=skywalker' \
--data-urlencode 'password=asdfasdfasd' \
https://${SITE_ID}.juju.io/api/v1/login
The response body is a JSON object containing all the user-provided fields except password. It also contains the created_at, updated_at, id, and session_token fields:
{
"username": "skywalker",
"created_at": "2011-11-07T20:58:34.448Z",
"updated_at": "2011-11-07T20:58:34.448Z",
"id": 12341234123412,
"session_token": "pnktnjyb996sj4p156gjtp4im"
}
The session_token is valid for 30 days.
Juju allows you to link your users with services like Twitter and Facebook, enabling your users to sign up or log into your application using their existing identities. This is accomplished through the sign-up and update REST endpoints by providing authentication data for the service you wish to link to a user in the authData field. Once your user is associated with a service, the auth_data for the service will be stored with the user and is retrievable by logging in.
auth_data is a JSON object with keys for each linked service containing the data below. In each case, you are responsible for completing the authentication flow (e.g. OAuth 1.0a/2.0) to obtain the information the the service requires for linking.
{
"facebook": {
"id": "user's Facebook id number as a string",
"access_token": "an authorized Facebook access token for the user",
"expiration_date": "token expiration date of the format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
}
}
{
"twitter": {
"id": "user's Twitter id number as a string",
"screen_name": "user's Twitter screen name",
"consumer_key": "your application's consumer key",
"consumer_secret": "your application's consumer secret",
"auth_token": "an authorized Twitter token for the user with your application",
"auth_token_secret": "the secret associated with the auth_token"
}
}
Signing a user up with a linked service and logging them in with that service uses the same POST request, in which the auth_data for the user is specified. For example, to sign up or log in with a user's Twitter account:
curl -X POST \
-H "Authorization: Juju ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"authData": {
"twitter": {
"id": "12345678",
"screen_name": "DuckMan123",
"consumer_key": "SaMpLeId3X7eLjjLgWEw",
"consumer_secret": "SaMpLew55QbMR0vTdtOACfPXa5UdO2THX1JrxZ9s3c",
"auth_token": "12345678-SaMpLeTuo3m2avZxh5cjJmIrAfx4ZYyamdofM7IjU",
"auth_token_secret": "SaMpLeEb13SpRzQ4DAIzutEkCE2LBIm2ZQDsP3WUU"
}
}
}' \
https://${SITE_ID}.juju.io/api/v1/login
Juju then verifies that the provided auth_data is valid and checks to see if a user is already associated with this data. If so, it returns a status code of 200 OK and the details (including a session_token for the user):
Status: 200 OK With a response body like:
{
"username": null,
"created_at": "2012-02-28T23:49:36.353Z",
"updated_at": "2012-02-28T23:49:36.353Z",
"id": 1234123412,
"session_token": "samplei3l83eerhnln0ecxgy5",
"authData": {
"twitter": {
"id": "12345678",
"screen_name": "DuckMan123",
"consumer_key": "SaMpLeId3X7eLjjLgWEw",
"consumer_secret": "SaMpLew55QbMR0vTdtOACfPXa5UdO2THX1JrxZ9s3c",
"auth_token": "12345678-SaMpLeTuo3m2avZxh5cjJmIrAfx4ZYyamdofM7IjU",
"auth_token_secret": "SaMpLeEb13SpRzQ4DAIzutEkCE2LBIm2ZQDsP3WUU"
}
}
}
Post to the /api/v1/logout URL:
curl -X POST \
-H "Authorization: Juju ${API_KEY}" \
-H "X-Juju-Session-Key: ${SESSION_KEY}" \
-H "Content-Type: application/json" \
https://${SITE_ID}.juju.io/api/v1/logout
Status will be 200 OK
The session key will now be deactivated.
Post to the /api/v1/forgot URL with either a valid username or email.
Note: the user's password will be reset to a random value and will be sent to them via email. If the user has no email defined the call will result in a 409 error.
curl -X POST \
-H "Authorization: Juju ${API_KEY}" \
-H "Content-Type: application/json" \
--data-urlencode 'username=skywalker' \
https://${SITE_ID}.juju.io/api/v1/forgot
Status will be 200 OK if successful.