Further API implmentation.
This commit is contained in:
		@@ -80,6 +80,10 @@ public class NLSongsDB {
 | 
			
		||||
            'UPDATE services SET "date" = ?, service_type = ? WHERE id = ?',
 | 
			
		||||
            [sdf.format(service.date), service.serviceType, service.id] ) }
 | 
			
		||||
 | 
			
		||||
    public int delete(Service service) {
 | 
			
		||||
        sql.execute("DELETE FROM services WHERE id = ?", [service.id])
 | 
			
		||||
        return sql.updateCount }
 | 
			
		||||
 | 
			
		||||
    /// ### Songs
 | 
			
		||||
    public Song findSong(int id) {
 | 
			
		||||
        def row = sql.firstRow("SELECT * FROM songs WHERE id = ?", [id])
 | 
			
		||||
@@ -126,6 +130,10 @@ public class NLSongsDB {
 | 
			
		||||
            "UPDATE songs SET name = ?, artists = ? WHERE id = ?",
 | 
			
		||||
            [song.name, wrapArtists(song.artists), song.id] ) }
 | 
			
		||||
 | 
			
		||||
    public int delete(Song song) {
 | 
			
		||||
        sql.execute("DELETE FROM songs WHERE id = ?", [song.id])
 | 
			
		||||
        return sql.updateCount }
 | 
			
		||||
 | 
			
		||||
    /// ### Performances
 | 
			
		||||
    public Performance findPerformance(int serviceId, int songId) {
 | 
			
		||||
        def perf = sql.firstRow(
 | 
			
		||||
@@ -162,34 +170,92 @@ public class NLSongsDB {
 | 
			
		||||
 | 
			
		||||
    public int delete(Performance perf) {
 | 
			
		||||
        sql.execute(
 | 
			
		||||
            "DELETE FROM performances WHERE service_id = ? AND song_id = ?")
 | 
			
		||||
        return sql.getUpdateCount() }
 | 
			
		||||
            "DELETE FROM performances WHERE service_id = ? AND song_id = ?",
 | 
			
		||||
            [perf.service_id, perf.song_id] )
 | 
			
		||||
        return sql.updateCount }
 | 
			
		||||
 | 
			
		||||
    /// ### API Keys
 | 
			
		||||
    public ApiKey findKey(String key) {
 | 
			
		||||
        def row = sql.firstRow("SELECT * FROM api_keys WHERE key = ?", [key])
 | 
			
		||||
        return recordToModel(row, ApiKey) }
 | 
			
		||||
    /// ### Users
 | 
			
		||||
    public List<User> findAllUsers() {
 | 
			
		||||
        return sql.rows("SELECT * FROM users").
 | 
			
		||||
            collect { buildUser(it); } }
 | 
			
		||||
        
 | 
			
		||||
    public User findUser(String username) {
 | 
			
		||||
        def row = sql.firstRow("SELECT * FROM users WHERE username = ?",
 | 
			
		||||
            [username])
 | 
			
		||||
        return buildUser(row) }
 | 
			
		||||
 | 
			
		||||
    public ApiKey save(ApiKey apiKey) {
 | 
			
		||||
        if (findKey(apiKey.key)) {
 | 
			
		||||
            update(apiKey)
 | 
			
		||||
            return apiKey }
 | 
			
		||||
        else return create(apiKey) }
 | 
			
		||||
    public User save(User user) {
 | 
			
		||||
        if (findUser(user.username)) {
 | 
			
		||||
            update(user); return user }
 | 
			
		||||
        else return create(user) }
 | 
			
		||||
 | 
			
		||||
    public ApiKey create(ApiKey apiKey) {
 | 
			
		||||
        sql.executeInsert(
 | 
			
		||||
            "INSERT INTO api_keys (key, description) VALUES (?, ?)",
 | 
			
		||||
            [apiKey.key, apiKey.description] )
 | 
			
		||||
    public User create(User user) {
 | 
			
		||||
        int newId = sql.executeInsert(
 | 
			
		||||
            "INSERT INTO users (username, pwd, role) VALUES (?, ?, ?)",
 | 
			
		||||
            [user.username, user.pwd, user.role])[0][0]
 | 
			
		||||
 | 
			
		||||
        return apiKey }
 | 
			
		||||
        user.id = newId
 | 
			
		||||
        return user }
 | 
			
		||||
 | 
			
		||||
    public int update(ApiKey apiKey) {
 | 
			
		||||
    public int update(User user) {
 | 
			
		||||
        return sql.executeUpdate(
 | 
			
		||||
            "UPDATE api_keys SET description = ? WHERE key = ?",
 | 
			
		||||
            [apiKey.description, apiKey.key]) }
 | 
			
		||||
            "UPDATE user SET username = ?, pwd = ?, role = ? WHERE id = ?",
 | 
			
		||||
            [user.username, user.pwd, user.role, user.id]) }
 | 
			
		||||
 | 
			
		||||
    /// ### User management
 | 
			
		||||
    // TODO
 | 
			
		||||
    public int delete(User user) {
 | 
			
		||||
        sql.execute("DELETE FROM users WHERE username = ?")
 | 
			
		||||
        return sql.updateCount }
 | 
			
		||||
 | 
			
		||||
    private static User buildUser(def row) {
 | 
			
		||||
        User user = new User(username: row["username"], role: row["role"])
 | 
			
		||||
        user.@pwd = row["pwd"]
 | 
			
		||||
 | 
			
		||||
        return user; }
 | 
			
		||||
 | 
			
		||||
    /// ### Tokens
 | 
			
		||||
    public Token findToken(String token) {
 | 
			
		||||
        def row = sql.firstRow("""\
 | 
			
		||||
            SELECT t.*, u.*
 | 
			
		||||
            FROM
 | 
			
		||||
                tokens t JOIN
 | 
			
		||||
                users u ON
 | 
			
		||||
                    t.user_id = u.id
 | 
			
		||||
            WHERE t.token = ?""", [token])
 | 
			
		||||
        return buildToken(row) }
 | 
			
		||||
 | 
			
		||||
    public Token renewToken(Token token) {
 | 
			
		||||
        def foundToken = findToken(token.token);
 | 
			
		||||
 | 
			
		||||
        // If the token has expired we will not renew it.
 | 
			
		||||
        if (new Date() > token.expires) return null;
 | 
			
		||||
 | 
			
		||||
        // Otherwise, renew and return the new values.
 | 
			
		||||
        assert sql.executeUpdate("UPDATE tokens SET " +
 | 
			
		||||
            "expires = current_timestamp + interval '1 day' WHEREtoken = ?", 
 | 
			
		||||
            [token.token]) == 1
 | 
			
		||||
 | 
			
		||||
        def updatedToken = findToken(token.token);
 | 
			
		||||
        token.expires = updatedToken.expires;
 | 
			
		||||
        return token; }
 | 
			
		||||
        
 | 
			
		||||
    public Token save(Token token) {
 | 
			
		||||
        if (findToken(token.token)) {
 | 
			
		||||
            update(token); return token }
 | 
			
		||||
        else return create(token) }
 | 
			
		||||
 | 
			
		||||
    public Token create(Token token) {
 | 
			
		||||
        sql.executeInsert("INSERT INTO tokens VALUES (?, ?, ?)",
 | 
			
		||||
            [token.token, token.user.id, token.expires])
 | 
			
		||||
        return Token }
 | 
			
		||||
 | 
			
		||||
    public int update(Token token) {
 | 
			
		||||
        return sql.executeUpdate(
 | 
			
		||||
            "UPDATE tokens SET expires = ? WHERE token = ?",
 | 
			
		||||
            [token.expires, token.token]) }
 | 
			
		||||
 | 
			
		||||
    public int delete(Token token) {
 | 
			
		||||
        sql.execute("DELETE FROM tokens WHERE token = ?", [token.token])
 | 
			
		||||
        return sql.updateCount }
 | 
			
		||||
 | 
			
		||||
    /// ### Utility functions
 | 
			
		||||
    static def recordToModel(def record, Class clazz) {
 | 
			
		||||
@@ -224,6 +290,12 @@ public class NLSongsDB {
 | 
			
		||||
            record[recordKey] = v }
 | 
			
		||||
        return record }
 | 
			
		||||
 | 
			
		||||
    private static Token buildToken(def row) {
 | 
			
		||||
        User user = buildUser(row)
 | 
			
		||||
 | 
			
		||||
        return new Token(
 | 
			
		||||
            token: row["token"], user: user, expires: row["expires"]) }
 | 
			
		||||
 | 
			
		||||
    public static List<String> unwrapArtists(String artists) {
 | 
			
		||||
        return artists.split(';') as List<String> }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								src/main/groovy/com/jdbernard/nlsongs/rest/PingResource.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/main/groovy/com/jdbernard/nlsongs/rest/PingResource.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
package com.jdbernard.nlsongs.rest;
 | 
			
		||||
 | 
			
		||||
import javax.ws.rs.GET;
 | 
			
		||||
import javax.ws.rs.Path;
 | 
			
		||||
import javax.ws.rs.Produces;
 | 
			
		||||
 | 
			
		||||
@Path("v1/ping") @AllowCors
 | 
			
		||||
public class PingResource {
 | 
			
		||||
 | 
			
		||||
    @GET
 | 
			
		||||
    @Produces("text/plain")
 | 
			
		||||
    public String ping() { return "pong"; } }
 | 
			
		||||
@@ -2,6 +2,7 @@ package com.jdbernard.nlsongs.rest;
 | 
			
		||||
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import javax.ws.rs.DELETE;
 | 
			
		||||
import javax.ws.rs.GET;
 | 
			
		||||
import javax.ws.rs.POST;
 | 
			
		||||
import javax.ws.rs.PUT;
 | 
			
		||||
@@ -38,6 +39,14 @@ public class ServicesResource {
 | 
			
		||||
        NLSongsContext.songsDB.update(service);
 | 
			
		||||
        return service; }
 | 
			
		||||
 | 
			
		||||
    @DELETE @Path("/{serviceId}")
 | 
			
		||||
    public Service deleteService(@PathParam("serviceId") int serviceId) {
 | 
			
		||||
        Service service = NLSongsContext.songsDB.findService(serviceId);
 | 
			
		||||
 | 
			
		||||
        if (service != null) { NLSongsContext.songsDB.delete(service); }
 | 
			
		||||
 | 
			
		||||
        return service; }
 | 
			
		||||
 | 
			
		||||
    @GET @Path("/withSong/{songId}")
 | 
			
		||||
    public List<Service> getServicesForSong(@PathParam("songId") int songId) {
 | 
			
		||||
        return NLSongsContext.songsDB.findServicesForSongId(songId); }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package com.jdbernard.nlsongs.rest;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import javax.ws.rs.DELETE;
 | 
			
		||||
import javax.ws.rs.GET;
 | 
			
		||||
import javax.ws.rs.POST;
 | 
			
		||||
import javax.ws.rs.PUT;
 | 
			
		||||
@@ -36,6 +37,14 @@ public class SongsResource {
 | 
			
		||||
        NLSongsContext.songsDB.update(song);
 | 
			
		||||
        return song; }
 | 
			
		||||
 | 
			
		||||
    @DELETE @Path("/{songId}")
 | 
			
		||||
    public Song deleteSong(@PathParam("songId") int songId) {
 | 
			
		||||
        Song song = NLSongsContext.songsDB.findSong(songId);
 | 
			
		||||
 | 
			
		||||
        if (song != null) { NLSongsContext.songsDB.delete(song); }
 | 
			
		||||
 | 
			
		||||
        return song; }
 | 
			
		||||
 | 
			
		||||
    @GET @Path("/forService/{serviceId}")
 | 
			
		||||
    public List<Song> getSongsForService(@PathParam("serviceId") int serviceId) {
 | 
			
		||||
        return NLSongsContext.songsDB.findSongsForServiceId(serviceId); }
 | 
			
		||||
@@ -43,4 +52,5 @@ public class SongsResource {
 | 
			
		||||
    @GET @Path("/byArtist/{artist}")
 | 
			
		||||
    public List<Song> getSongsForArtist(@PathParam("artist") String artist) {
 | 
			
		||||
        return NLSongsContext.songsDB.findSongsByArtist(artist); }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
package com.jdbernard.nlsongs.rest;
 | 
			
		||||
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import javax.annotation.security.RolesAllowed;
 | 
			
		||||
import javax.annotation.security.PermitAll;
 | 
			
		||||
import javax.ws.rs.DELETE;
 | 
			
		||||
import javax.ws.rs.GET;
 | 
			
		||||
import javax.ws.rs.POST;
 | 
			
		||||
import javax.ws.rs.PUT;
 | 
			
		||||
import javax.ws.rs.Consumes;
 | 
			
		||||
import javax.ws.rs.Path;
 | 
			
		||||
import javax.ws.rs.PathParam;
 | 
			
		||||
import javax.ws.rs.Produces;
 | 
			
		||||
import javax.ws.rs.core.Context;
 | 
			
		||||
import javax.ws.rs.core.MediaType;
 | 
			
		||||
import javax.ws.rs.core.Response;
 | 
			
		||||
import javax.ws.rs.core.SecurityContext;
 | 
			
		||||
 | 
			
		||||
import com.jdbernard.nlsongs.servlet.NLSongsContext;
 | 
			
		||||
import com.jdbernard.nlsongs.model.User;
 | 
			
		||||
import com.jdbernard.nlsongs.model.Token;
 | 
			
		||||
 | 
			
		||||
@Path("v1/users") @AllowCors @PermitAll
 | 
			
		||||
@Produces({MediaType.APPLICATION_JSON})
 | 
			
		||||
@Consumes({MediaType.APPLICATION_JSON})
 | 
			
		||||
public class UsersResource {
 | 
			
		||||
 | 
			
		||||
    @Context SecurityContext secCtx;
 | 
			
		||||
 | 
			
		||||
    @GET @RolesAllowed("admin")
 | 
			
		||||
    public List<User> getUsers() {
 | 
			
		||||
        return NLSongsContext.songsDB.findAllUsers(); }
 | 
			
		||||
 | 
			
		||||
    @POST @RolesAllowed("admin")
 | 
			
		||||
    public User postUser(User user) {
 | 
			
		||||
        return NLSongsContext.songsDB.create(user); }
 | 
			
		||||
 | 
			
		||||
    @GET @Path("/{username}")
 | 
			
		||||
    public Response getUser(@PathParam("username") String username) {
 | 
			
		||||
 | 
			
		||||
        // If they are looking up their own information, OK.
 | 
			
		||||
        if (username == secCtx.getUserPrincipal().getName() ||
 | 
			
		||||
            // Or if they are an admin, OK.
 | 
			
		||||
            secCtx.isUserInRole("admin")) {
 | 
			
		||||
 | 
			
		||||
            return Response.ok(
 | 
			
		||||
                NLSongsContext.songsDB.findUser(username)).build(); }
 | 
			
		||||
 | 
			
		||||
        else return Response.status(Response.Status.FORBIDDEN).build(); }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @PUT @Path("/{username}")
 | 
			
		||||
    public Response putUser(@PathParam("username") String username, User user) {
 | 
			
		||||
 | 
			
		||||
        // If they are looking up their own information, OK.
 | 
			
		||||
        if (username == secCtx.getUserPrincipal().getName() ||
 | 
			
		||||
            // Or if they are an admin, OK.
 | 
			
		||||
            secCtx.isUserInRole("admin")) {
 | 
			
		||||
 | 
			
		||||
            NLSongsContext.songsDB.update(user);
 | 
			
		||||
 | 
			
		||||
            return Response.ok(user).build(); }
 | 
			
		||||
 | 
			
		||||
        else return Response.status(Response.Status.FORBIDDEN).build(); }
 | 
			
		||||
 | 
			
		||||
    @DELETE @Path("/{username}")
 | 
			
		||||
    public Response deleteUser(@PathParam("username") String username) {
 | 
			
		||||
 | 
			
		||||
        // If they are looking up their own information, OK.
 | 
			
		||||
        if (username == secCtx.getUserPrincipal().getName() ||
 | 
			
		||||
            // Or if they are an admin, OK.
 | 
			
		||||
            secCtx.isUserInRole("admin")) {
 | 
			
		||||
 | 
			
		||||
            User user = NLSongsContext.songsDB.findUser(username);
 | 
			
		||||
            
 | 
			
		||||
            if (user != null) NLSongsContext.songsDB.delete(user);
 | 
			
		||||
 | 
			
		||||
            return Response.ok(user).build(); }
 | 
			
		||||
 | 
			
		||||
        else return Response.status(Response.Status.FORBIDDEN).build(); }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user