9 Commits
v2.0 ... v2.3

Author SHA1 Message Date
58b00cbdb0 Migrated source documentation to doc.jdb-labs.com. 2015-05-12 20:51:58 -05:00
f551165a82 Increment minor version number. New work belongs on v2.3 2015-04-14 15:48:49 -05:00
e89b2e0a02 Added service descriptions.
Pages now use service descriptions to describe services, falling back on the
service type's displayable value if no description is given.
2015-04-14 15:13:21 -05:00
c7bee5009a Continued work on API documentation. 2015-04-10 19:14:30 -05:00
cad957394e Fleahed out documentation. 2015-04-09 21:47:48 -05:00
8eb7918f7f Added favicon in ICO format. 2015-03-30 21:07:17 -05:00
b7970f6af8 Increment minor version so new work is on v2.2 2015-03-30 02:17:49 -05:00
4580709d29 Version 2.1: Default to MP3s instead of OGGs for song files. 2015-03-30 02:15:06 -05:00
2bf0412629 Increment minor version so new work is on v2.1. 2015-03-23 04:16:09 -05:00
12 changed files with 260 additions and 50 deletions

8
README.md Normal file
View File

@ -0,0 +1,8 @@
# New Life Songs Database
This is Jonathan's database of worship songs performed at New Life Austin. The
service lives online at http://newlifesongs.jdbernard.com
API Documentation is [maintained online with the service](http://newlifesongs.jdbernard.com/doc/api/v1/).
You can also view the [annotated source code](https://doc.jdb-labs.com/new-life-songs/current/).

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -7,6 +7,7 @@ public class Service implements Serializable {
int id
private LocalDate date
ServiceType serviceType
String description
public boolean equals(Object thatObj) {
if (thatObj == null) return false

View File

@ -13,5 +13,5 @@ public class NLSongsContext {
public static String makeUrl(Service service, Song song) {
return mediaBaseUrl + '/' + service.@date.toString('yyyy-MM-dd') + '_' +
service.serviceType.name().toLowerCase() + '_' +
song.name.replaceAll(/[\s'"\\\/\?!]/, '') + '.ogg' }
song.name.replaceAll(/[\s'"\\\/\?!]/, '') + '.mp3' }
}

View File

@ -9,6 +9,7 @@ CREATE TABLE IF NOT EXISTS services (
id SERIAL,
date DATE NOT NULL,
service_type VARCHAR(16) DEFAULT NULL,
description VARCHAR(255) DEFAULT NULL,
CONSTRAINT uc_serviceTypeAndDate UNIQUE (date, service_type),
PRIMARY KEY (id));

View File

@ -65,7 +65,11 @@ table {
pre { margin-left: 1rem; }
h3 { margin: 1rem 0; }
h2 {
border-bottom: solid 2px $dark;
margin-top: 2em; }
h3 { margin: 2rem 0 1rem 0; }
dl {
margin: 1rem;
@ -75,7 +79,20 @@ table {
font-family: $monoFont;
font-weight: bold; }
& > dd { padding: 0 0 0.5rem 1rem; } } }
& > dd { padding: 0 0 0.5rem 1rem; } }
table.method-summary {
padding: 0 2rem;
width: 100%;
th {
border-bottom: solid thin $dark;
text-align: left; }
th.action, td.action { width: 6em; }
th.path, td.path { width: 17em; }
th.public, td.public { width: 4em; }
} }
@include forSize(notSmall) {
@ -109,7 +126,7 @@ table {
text-align: center;
& > h2 { display: none; }
& > h2.song-name, & > h2.service-date { display: block; }
& > h2.song-name, & > h2.service-desc { display: block; }
& > nav > ul > li {
display: inline-block;

View File

@ -21,8 +21,8 @@
</header>
<section id=api-overview>
The New Life Songs database exposes a REST API. This allows
programatic access and modification to the data. Version 1 of the
API defines several endpoints, all of which are built off of
programatic access to and modification of the data. Version 1 of
the API defines several endpoints, all of which are built off of
<code>http://newlifesongs.jdbernard.com/api/v1</code> as a base
URL.
@ -64,6 +64,46 @@
"Michael W. Smith"
]
}</pre>
<h3>Method Summary</h3>
<table class=method-summary>
<thead>
<tr><th class=action>HTTP Action</th>
<th class=path>Path</th>
<th class=desc>Description</th>
<th class=public>Public?</th></tr>
</thead>
<tbody>
<tr><td class=action>GET</td>
<td class=path><code>/songs</code></td>
<td class=desc>Retrieve all songs.</td>
<td class=public>yes</td></tr>
<tr><td class=acion>POST</td>
<td class=path><code>/songs</code></td>
<td class=desc>Create a new song record.</td>
<td class=public>no</td></tr>
<tr><td class=acion>GET</td>
<td class=path><code>/songs/&lt;songId&gt;</code></td>
<td class=desc>Retrieve a single record.</td>
<td class=public>yes</td></tr>
<tr><td class=acion>PUT</td>
<td class=path><code>/songs/&lt;songId&gt;</code></td>
<td class=desc>Update a song record.</td>
<td class=public>no</td></tr>
<tr><td class=acion>DELETE</td>
<td class=path><code>/songs/&lt;songId&gt;</code></td>
<td class=desc>Delete a song record.</td>
<td class=public>no</td></tr>
<tr><td class=acion>GET</td>
<td class=path><code>/songs/forService/&lt;serviceId&gt;</code></td>
<td class=desc>Retrieve all songs performed in a given service.</td>
<td class=public>yes</td></tr>
<tr><td class=acion>GET</td>
<td class=path><code>/songs/byArtist/&lt;artist&gt;</code></td>
<td class=desc>Retrieve all songs performed by a given artist.</td>
<td class=public>yes</td></tr>
</tbody>
</table>
<ul class=method-list>
<li><h3><code>GET /songs</code></h3>
@ -71,22 +111,22 @@
<p><h4>Response</h4>
A list of <a href="song-object">song objects</a>
<h4>Example</h4>
<p><h4>Example</h4>
<pre>
GET http://newlifesongs.jdbernard.com/api/v1/songs</pre>
<p><pre>
HTTP/1.1 200 OK
Content-Length: 5146
Content-Length: 433
Content-Type: application/json
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Server: Jetty(6.1.25)
[{"id":1,"name":"Welcome Holy Spirit","artists":["Mark Condon"]},
{"id":3,"name":"Let's Sing Praises to our God","artists":["Traditional"]},
{"id":5,"name":"Blessed Assurance","artists":["Frances J. Crosby"]},
{"id":8,"name":"Here I Am To Worship","artists":["Tim Hughes", "Chris Tomlin", "Michael W. Smith"]},
{"id":12,"name":"Healer","artists":["Kari Jobe", "Hillsong"]},
{"id":15,"name":"I Am Free","artists":["Newsboys"]}]</pre></li>
{"id":15,"name":"I Am Free","artists":["Newsboys"]}]
</pre></li>
<li><h3><code>POST /songs</code></h3>
@ -105,10 +145,185 @@ Server: Jetty(6.1.25)
The newly-created song record.
<p><h4>Example</h4>
<pre>
</pre></li>
<li><h3><code>GET /songs/&lt;songId&gt;</code></h3>
<p>Retrieve song data for the given song id.
<p><h4>Response</h4>
A <a href="song-object">song object</a>.
<p><h4>Example</h4>
<pre>
GET http://newlifesongs.jdbernard.com/api/v1/songs/1</pre>
<p><pre>
HTTP/1.1 200 OK
Content-Length: 63
Content-Type: application/json
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
{"id":1,"name":"Welcome Holy Spirit","artists":["Mark Condon"]}
</pre></li>
</li>
<li><h3><code>PUT /songs/&lt;songId&gt;</code></h3>
<p>Method description
<p><h4>Request Body</h4>
Request body description
<p><h4>Response</h4>
Return value description
<p><h4>Example</h4>
<pre>
</pre></li>
</li>
<li><h3><code>DELETE /songs/&lt;songId&gt;</code></h3>
<p>Method description
<p><h4>Request Body</h4>
Request body description
<p><h4>Response</h4>
Return value description
<p><h4>Example</h4>
<pre>
</pre></li>
</li>
<li><h3><code>GET /songs/forService/&lt;serviceId&gt;</code></h3>
<p>Method description
<p><h4>Request Body</h4>
Request body description
<p><h4>Response</h4>
Return value description
<p><h4>Example</h4>
<pre>
GET /api/v1/songs/forService/1 HTTP/1.1</pre>
<p><pre>
HTTP/1.1 200 OK
Content-Length: 256
Content-Type: application/json
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
[{"id":7,"name":"Mighty God","artists":[""]},
{"id":8,"name":"Here I Am To Worship","artists":["Tim Hughes: Chris Tomlin, Michael W. Smith"]},
{"id":9,"name":"Worthy","artists":[""]},
{"id":4,"name":"I Am A Friend Of God","artists":["Israel Houghton"]}]j
</pre></li>
</li>
<li><h3><code>GET /songs/byArtist/&lt;artist&gt;</code></h3>
<p>Method description
<p><h4>Request Body</h4>
Request body description
<p><h4>Response</h4>
Return value description
<p><h4>Example</h4>
<pre>
</pre></li>
</li>
</section>
<section id=services>
<h2><code>/services</code></h2>
<h3 id=service-object>Service object</h3>
A Service object is defined with the following fields:
<dl><dt>id</dt>
<dd>An identifier unique to this service record among all
service records. <em>Type: integer</em></dd>
<dt>date</dt>
<dd>The date of the service. <em>Type: Date</em></dd>
<dt>serviceType</dt>
<dd>Service type. <em>Type: string</em> Valid values:
<table><thead><tr><th>Value</th><th>Description</th></tr></thead>
<tbody>
<tr><td><code>SUN_AM</code></td>
<td>Sunday morning service.</td></tr>
<tr><td><code>SUN_PM</code></td>
<td>Sunday evening service</td></tr>
<tr><td><code>WED</code></td>
<td>Wednesday, midweek Bible study.</td></tr>
</tbody>
</table>
</dd>
</dl>
<h4>Example</h4>
<pre>
{
"id": 1,
"date": 1235887200000,
"serviceType": "SUN_PM"
}</pre>
<h3>Method Summary</h3>
<table class=method-summary>
<thead>
<tr><th class=action>HTTP Action</th>
<th class=path>Path</th>
<th class=desc>Description</th>
<th class=public>Public?</th></tr>
</thead>
<tbody>
<tr><td class=action>GET</td>
<td class=path><code>/services</code></td>
<td class=desc>Retrieve all services.</td>
<td class=public>yes</td></tr>
<tr><td class=acion>POST</td>
<td class=path><code>/services</code></td>
<td class=desc>Create a new service record.</td>
<td class=public>no</td></tr>
<tr><td class=acion>GET</td>
<td class=path><code>/services/&lt;serviceId&gt;</code></td>
<td class=desc>Retrieve a single service record.</td>
<td class=public>yes</td></tr>
<tr><td class=acion>PUT</td>
<td class=path><code>/services/&lt;serviceId&gt;</code></td>
<td class=desc>Update a service record.</td>
<td class=public>no</td></tr>
<tr><td class=acion>DELETE</td>
<td class=path><code>/services/&lt;serviceId&gt;</code></td>
<td class=desc>Delete a service record.</td>
<td class=public>no</td></tr>
<tr><td class=acion>GET</td>
<td class=path><code>/services/withSong/&lt;serviceId&gt;</code></td>
<td class=desc>Retrieve all services in which the given song was performed.</td>
<td class=public>yes</td></tr>
<tr><td class=acion>GET</td>
<td class=path><code>/services/byDate/after/&lt;date&gt;</code></td>
<td class=desc>Retrieve all services after the given date.</td>
<td class=public>yes</td></tr>
<tr><td class=acion>GET</td>
<td class=path><code>/services/byDate/before/&lt;date&gt;</code></td>
<td class=desc>Retrieve all services before the given date.</td>
<td class=public>yes</td></tr>
<tr><td class=acion>GET</td>
<td class=path><code>/services/byDate/between/&lt;date1&gt;/&lt;date2&gt;</code></td>
<td class=desc>Retrieve all services between the two given dates.</td>
<td class=public>yes</td></tr>
</tbody>
</table>
</section>
<section id=users>
<h2><code>/users</code></h2>

View File

@ -38,8 +38,8 @@ if (!service) { response.sendError(response.SC_NOT_FOUND); return }
<body>
<header>
<h1><a href="../">New Life Songs</a></h1>
<h2 class=service-date><%= service.@date.toString("yyyy-MM-dd") %> (<%=
service.serviceType.displayName %>)</h2>
<h2 class=service-desc><%= service.@date.toString("yyyy-MM-dd") %>: (<%=
service.description ?: service.serviceType.displayName %>)</h2>
<nav><ul>
<li><a href="../admin/">Admin</a></li>

View File

@ -45,7 +45,8 @@ songsDB = NLSongsContext.songsDB
<% songsDB.findAllServices().sort { it.date }.reverse().each { service -> %>
<tr><td class=date><a href="../service/<%= service.id %>"><%=
service.@date.toString("yyyy-MM-dd") %></a></td>
<td class=service-type><%= service.serviceType.displayName %></td></tr><% } %>
<td class=service-type><%= service.description ?:
service.serviceType.displayName %></td></tr><% } %>
</tbody>
<!--<tfoot><tr>
<th class="dt-left">Date</th>

View File

@ -5,8 +5,7 @@ import com.jdbernard.nlsongs.model.*
import java.text.SimpleDateFormat
sdf = new SimpleDateFormat('yyyy-MM-dd')
hcfg = new
HikariConfig("/home/jdbernard/projects/new-life-songs/src/main/webapp/WEB-INF/classes/datasource.properties")
hcfg = new HikariConfig("/home/jdbernard/projects/new-life-songs/src/main/webapp/WEB-INF/classes/datasource.properties")
makeService = { svcRow ->
Service svc = new Service()

View File

@ -1,32 +0,0 @@
package com.jdbernard.nlsongs.db
public class GenerateQueries {
public static void main(String[] args) {
}
public static Map<String, Map<String, String> > generateQueries(String ddl) {
def tables = [:]
// Find the table definitions
String tableRegex = /(?ms)(?:CREATE TABLE (?:IF NOT EXISTS )?([^\s]+) \(([^\s]+);.+?)+/
ddl.eachMatch(tableRegex) { matchGroups ->
String tableName = matchGroups[1]
// Parse the column definitions.
// Create new record insert statements.
// Create insert queries.
// Create update queries.
// Create delete queries.
// Create ID lookup queries.
}
}

View File

@ -1,6 +1,6 @@
#
#Mon Mar 23 03:03:08 CDT 2015
#Tue May 12 20:51:08 CDT 2015
major=2
version.release=true
minor=0
build=101
minor=3
build=0