public class AuthenticationBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(AuthenticationService.class).to(AuthenticationService.class);
    }
} public class BucketBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(PictureBucket.class).to(PictureBucket.class);
    }
} @Path("/auth/email")
public class AuthEmailController {
    @Inject
    EmailRepository emailRepository;
    
    @Inject
    AuthenticationService authenticationService;

    /**
     * @api {post} /auth/email Authenticate using email and password
     * @apiGroup User
     * 
     * @apiParam {String} email
     * @apiParam {String} password
     *
     * @apiParamExample {json} Request-Example:
     *     {
     *      "email": "test@test.org",
     *      "password": "123456"
     *     }
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     *
     * @apiSuccessExample Success-Response:
     *     {
     *       "token": "ZjY4MDc5YmUtMmMyMy00MWRkLTljYTItMGNjNmFhMzY4YzVhLiQyYSQxMiRKNHBiSzguRm5SazFKMUlodHVJZVEuNnFsR1dxakNwZjBqRTc3LnlYVTIyNHJIcEVFWU9WLg=="
     *     }
     */
    @POST
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public ObjectNode auth(@Valid AuthInput input) {
        Email email = emailRepository.load(input.getEmail());
        
        if (email == null || !Email.checkPassword(input.getPassword(), email.getPassword())) {
            throw new ForbiddenException("Invalid email or password");
        }
        
        return new ObjectMapper().createObjectNode().put("token", authenticationService.generateToken(email.getUserguid()));
    }

    public static class AuthInput {
        @NotNull
        private String email;
        
        @NotNull
        private String password;

        public String getEmail() {
            return email;
        }

        public void setEmail(String email) {
            this.email = email;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }
}
 @Path("/auth/facebook")
public class AuthFacebookController {
    @Inject
    WebRequestor webRequestor;

    @Inject
    EmailRepository emailRepository;

    @Inject
    UserRepository userRepository;

    @Inject
    FacebookUserRepository facebookUserRepository;
    
    @Inject
    AuthenticationService authenticationService;

    /**
     * @api {post} /auth/facebook Authenticate using Facebook token
     * @apiGroup User
     * 
     * @apiParam {String} token Facebook token
     *
     * @apiParamExample {json} Request-Example:
     *     {
     *      "token": "PYUcuKy9AS1dzfg5ZAykalms0v7OIWr3gaRZAJntrZAVURqcdZAoqlxNglQCNauZCwWHmTZAhmGGoG3clNKG7gTLV3uonzBlFVaIWGZAbrJchrTQ97AVia6ICeWqeXwg37n1XSxdXjLzQslLTV2W6CBABZB91awfooABNX7Sz6ttTbr0U2esM6uhkcLk5hAinGY7Ff99mqDECRbOOk1xRn9Ha"
     *     }
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     *
     * @apiSuccessExample Success-Response:
     *     {
     *       "token": "ZjY4MDc5YmUtMmMyMy00MWRkLTljYTItMGNjNmFhMzY4YzVhLiQyYSQxMiRKNHBiSzguRm5SazFKMUlodHVJZVEuNnFsR1dxakNwZjBqRTc3LnlYVTIyNHJIcEVFWU9WLg=="
     *     }
     */
    @POST
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public ObjectNode auth(@Valid AuthFacebookInput input) {
        final FacebookUser facebookUser = facebookUserRepository.load(input.getToken());
        
        final String guid;
        
        if (facebookUser == null) {
            FacebookClient facebookClient = new DefaultFacebookClient(input.getToken(), webRequestor,
                    new DefaultJsonMapper(), Version.VERSION_2_5);
            
            FacebookResponse facebookResponse = facebookClient.fetchObject("me", FacebookResponse.class,
                    Parameter.with("fields", "id,first_name,last_name,email,location,link"));
            
            final Email email = emailRepository.load(facebookResponse.getEmail());
            
            if (email == null) {
                guid = UUID.randomUUID().toString();
                
                final User newUser = new User();
                newUser.setGuid(guid);
                newUser.setFirstname(facebookResponse.getFirstname());
                newUser.setLastname(facebookResponse.getLastname());
                newUser.setEmail(facebookResponse.getEmail());
                
                final Email newEmail = new Email();
                newEmail.setUserguid(guid);
                newEmail.setEmail(facebookResponse.getEmail());
                
                //TODO made it asynchronous
                emailRepository.save(newEmail);
                userRepository.save(newUser);
            } else {
                guid = email.getUserguid();
            }
            
            final FacebookUser newFacebookUser = new FacebookUser();
            
            newFacebookUser.setUserguid(guid);
            newFacebookUser.setToken(input.getToken());
            newFacebookUser.setId(facebookResponse.getId());
            newFacebookUser.setLocation(facebookResponse.getLocation());
            newFacebookUser.setLink(facebookResponse.getLink());
            
            facebookUserRepository.save(newFacebookUser);
        } else {
            guid = facebookUser.getUserguid();
        }
        
        return new ObjectMapper().createObjectNode().put("token", authenticationService.generateToken(guid));
    }

    public static class AuthFacebookInput {
        @NotNull
        private String token;

        public String getToken() {
            return token;
        }

        public void setToken(String token) {
            this.token = token;
        }
    }

    public static class FacebookResponse {
        @Facebook
        public String id;
        
        @Facebook("first_name")
        public String firstname;
        
        @Facebook("last_name")
        public String lastname;
        
        @Facebook
        public String email;
        
        @Facebook
        public String location;
        
        @Facebook
        public String link;

        public String getId() {
            return id;
        }

        public String getFirstname() {
            return firstname;
        }

        public String getLastname() {
            return lastname;
        }

        public String getEmail() {
            return email;
        }

        public String getLocation() {
            return location;
        }

        public String getLink() {
            return link;
        }
    }
}
 @Path("/focus")
public class FocusController {
    @Inject FocusIndexer focusIndexer;
    @Inject FocusRepository focusRepository;

    /**
     * @api {post} /focus/query Search focus inside a squared area
     * @apiGroup Focus
     * 
     * @apiParam {String} latlonnw Northwestern latitude and longitude
     * @apiParam {String} latlonse Southeastern latitude and longitude
     *
     * @apiParamExample {json} Request-Example:
     *     {
     *       "latlonnw": "-22.6993761,-47.4095964",
     *       "latlonse": "-24.6993761,-45.4095964"
     *     }
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     *
     * @apiSuccessExample Success-Response:
     *     [
     *       {
     *         "latlon": "-23.6993761,-46.4095964",
     *         "authoruserguid": "f68079be-2c23-41dd-9ca2-0cc6aa368c5a",
     *         "guid": "c6e376cb-2e3b-4721-b22b-0c07eb06a835",
     *         "thumbsup": "0",
     *         "createdat": "1457646582199"
     *       },
     *       {
     *         "latlon": "-23.697866,-46.408891",
     *         "authoruserguid": "f68079be-2c23-41dd-9ca2-0cc6aa368c5a",
     *         "guid": "c329f1ea-78b6-42a6-ac7e-b7959a0ef8f8",
     *         "thumbsup": "0",
     *         "createdat": "1457646640229"
     *       }
     *     ]
     */
    @POST
    @Path("/query")
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public Object query(@Valid FocusQueryInput input) {
        return focusIndexer.search(input.getLatlonnw(), input.getLatlonse());
    }
    
    /**
     * @api {post} /focus/query-center Search focuses near by a single point
     * @apiGroup Focus
     * 
     * @apiParam {String} latlon Latitude and longitude
     *
     * @apiParamExample {json} Request-Example:
     *     {
     *       "latlon": "-23.6993761,-46.4095964",
     *     }
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     *
     * @apiSuccessExample Success-Response:
     *     [
     *       {
     *         "latlon": "-23.6993761,-46.4095964",
     *         "authoruserguid": "f68079be-2c23-41dd-9ca2-0cc6aa368c5a",
     *         "guid": "c6e376cb-2e3b-4721-b22b-0c07eb06a835",
     *         "thumbsup": "0",
     *         "createdat": "1457646582199"
     *       },
     *       {
     *         "latlon": "-23.697866,-46.408891",
     *         "authoruserguid": "f68079be-2c23-41dd-9ca2-0cc6aa368c5a",
     *         "guid": "c329f1ea-78b6-42a6-ac7e-b7959a0ef8f8",
     *         "thumbsup": "0",
     *         "createdat": "1457646640229"
     *       }
     *     ]
     */
    @POST
    @Path("/query-center")
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public Object queryCenter(@Valid FocusCenterInput input) {
        return focusIndexer.searchCenter(input.getLatlon());
    }
    
    /**
     * @api {GET} /:guid Show focus details
     * @apiGroup Focus
     * 
     * @apiParam {String} guid Focus guid
     *
     * @apiParamExample {json} Request-Example:
     *     /focus/d35d4485-9dc1-4f44-880e-f94bf773c420
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     *
     * @apiSuccessExample Success-Response:
     *     {
     *       "guid": "d35d4485-9dc1-4f44-880e-f94bf773c420",
     *       "createdat": "1457998498349",
     *       "latlon": "-23.6993761,-46.4095964",
     *       "notes": "Lots of tires near 2th Street",
     *       "thumbsup": "0",
     *       "authoruserguid": "f68079be-2c23-41dd-9ca2-0cc6aa368c5a"
     *     }
     */
    @GET
    @Path("{guid}")
    @Produces("application/json;charset=UTF-8")
    public Focus details(@PathParam("guid") String guid) {
        return focusRepository.loadOrNotFound(guid);
    }

    public static class FocusQueryInput {
        @NotNull
        private String latlonnw;
        
        @NotNull
        private String latlonse;

        public String getLatlonnw() {
            return latlonnw;
        }

        public void setLatlonnw(String latlonnw) {
            this.latlonnw = latlonnw;
        }

        public String getLatlonse() {
            return latlonse;
        }

        public void setLatlonse(String latlonse) {
            this.latlonse = latlonse;
        }
    }
    
    public static class FocusCenterInput {
        @NotNull
        private String latlon;

        public String getLatlon() {
            return latlon;
        }

        public void setLatlon(String latlon) {
            this.latlon = latlon;
        }
    }
}
 @Path("/healthcheck")
public class HealthCheckController {
    @GET
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public ObjectNode query() {
        return new ObjectMapper().createObjectNode().put("status", "ok");
    }
}
 @Path("/picture")
public class PictureController {
    @Inject
    PictureRepository pictureRepository;
    @Inject
    FocusRepository focusRepository;
    @Inject
    PictureBucket pictureBucket;
    @Inject
    User user;

    /**
     * @api {post} /picture/focus/:guid Attach a picture into a facus
     * @apiGroup Focus
     * 
     * @apiParam {String} guid Focus guid
     *
     * @apiParamExample {json} Request-Example:
     *     {
     *      "TODO": "TODO"
     *     }
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     *
     * @apiSuccessExample Success-Response:
     *     {
     *       "TODO": "TODO"
     *     }
     */
    @POST
    @Consumes({ MediaType.MULTIPART_FORM_DATA })
    @Produces("application/json;charset=UTF-8")
    @Path("/focus/{focusguid}")
    public Picture post(@PathParam("focusguid") String focusguid, @FormDataParam("file") InputStream fileInputStream,
            @FormDataParam("file") FormDataContentDisposition fileDisposition) {
        Focus focus = focusRepository.loadOrNotFound(focusguid);
        
        if (!user.getGuid().equals(focus.getAuthoruserguid())) {
            throw new BadRequestException("User does not own this item");
        }
        
        Picture picture = new Picture();
        picture.setGuid(UUID.randomUUID().toString());
        picture.setFilename(fileDisposition.getFileName());
        picture.setFocusGuid(focusguid);
        picture.setCreatedat(Long.toString(new Date().getTime()));
        
        pictureBucket.put(picture.getPath(), fileInputStream, fileDisposition.getSize());
        pictureRepository.save(picture);

        return picture;
    }
}
 @Path("/focus")
public class PostFocusController {
    @Inject
    FocusRepository focusRepository;
    @Inject
    FocusIndexer focusIndexer;
    @Inject
    User currentUser;

    /**
     * @api {post} /focus Create a new focus
     * @apiGroup Focus
     * 
     * @apiParam {String} latlon Latitude and longitude
     * @apiParam {String} notes
     *
     * @apiParamExample {json} Request-Example:
     *     {
     *       "latlon": "-23.6993761,-46.4095964",
     *       "notes": "Lots of tires near 2th Street"
     *     }
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     *
     * @apiSuccessExample Success-Response:
     *     {
     *       "guid": "b64c60d2-c18d-4f19-ac7d-5ecf6039103c",
     *       "latlon": "-23.6993761,-46.4095964",
     *       "notes": "Lots of tires near 2th Street",
     *       "thumbsup": "0",
     *       "authoruserguid": "f68079be-2c23-41dd-9ca2-0cc6aa368c5a",
     *       "createdat": "1457995237696"
     *     }
     */
    @POST
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public Focus post(@Valid FocusPostInput input) {
        Focus focus = new Focus();
        focus.setGuid(java.util.UUID.randomUUID().toString());
        focus.setLatlon(input.getLatlon());
        focus.setNotes(input.getNotes());
        focus.setAuthoruserguid(currentUser.getGuid());
        focus.setThumbsup(0);
        focus.setCreatedat(Long.toString(new Date().getTime()));

        focusRepository.save(focus);
        focusIndexer.index(focus);

        return focus;
    }

    public static class FocusPostInput {
        @NotNull
        private String latlon;
        
        private String notes;

        public String getLatlon() {
            return latlon;
        }

        public void setLatlon(String latlon) {
            this.latlon = latlon;
        }

        public String getNotes() {
            return notes;
        }

        public void setNotes(String notes) {
            this.notes = notes;
        }
    }
}
 @Path("/profile")
public class ProfileController {
    @Inject UserRepository userRepository;
    @Inject User currentUser;

    /**
     * @api {get} /profile Show user profile details
     * @apiGroup User
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     *
     * @apiSuccessExample Success-Response:
     *     {
     *       "guid": "f68079be-2c23-41dd-9ca2-0cc6aa368c5a",
     *       "email": "test@test.org",
     *       "firstname": "Rogério",
     *       "lastname": "Yokomizo",
     *       "location": null,
     *       "facebookurl": null,
     *       "twitter": null,
     *       "profilepictureguid": null
     *     }
     */
    @GET
    @Produces("application/json;charset=UTF-8")
    public User get() {
        return currentUser;
    }
    
    @POST
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public User post(@Valid ProfilePostInput input) {
        currentUser.setFirstname(input.getFirstname());
        currentUser.setLastname(input.getLastname());
        currentUser.setLocation(input.getLocation());
        currentUser.setFacebookurl(input.getFacebookurl());
        currentUser.setTwitter(input.getTwitter());
        
        userRepository.save(currentUser);
        
        return currentUser;
    }

    public static class ProfilePostInput {
        @NotNull
        @NotEmpty
        private String firstname;
        
        private String lastname;
        
        private String location;
        
        private String facebookurl;
        
        private String twitter;

        public String getFirstname() {
            return firstname;
        }

        public void setFirstname(String firstname) {
            this.firstname = firstname;
        }

        public String getLastname() {
            return lastname;
        }

        public void setLastname(String lastname) {
            this.lastname = lastname;
        }

        public String getLocation() {
            return location;
        }

        public void setLocation(String location) {
            this.location = location;
        }

        public String getFacebookurl() {
            return facebookurl;
        }

        public void setFacebookurl(String facebookurl) {
            this.facebookurl = facebookurl;
        }

        public String getTwitter() {
            return twitter;
        }

        public void setTwitter(String twitter) {
            this.twitter = twitter;
        }
    }
}
 @Path("/reset-password")
public class ResetPasswordController {
    @Inject
    PasswordResetTokenRepository passwordResetTokenRepository;
    
    @Inject
    EmailRepository emailRepository;

    /**
     * @api {post} /reset-password/request Request a password reset token
     * @apiGroup User
     * 
     * @apiParam {String} email
     *
     * @apiParamExample {json} Request-Example:
     *     {
     *       "email": "test@test.org"
     *     }
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     */
    @POST
    @Path("/request")
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public ObjectNode request(@Valid RequestResetPasswordInput input) {
        String code = UUID.randomUUID().toString();
        
        Email email = emailRepository.load(input.getEmail());
        
        PasswordResetToken token = new PasswordResetToken();
        token.setEmail(email.getEmail());
        token.setUserguid(email.getUserguid());
        token.setToken(PasswordResetToken.encryptToken(code));
        token.setExpires(Long.toString(LocalDateTime.now().plusDays(5).toEpochSecond(ZoneOffset.UTC)));
        
        String publicToken = Base64.getEncoder().encodeToString((token.getExpires() + "." + code).getBytes()); 
        
        passwordResetTokenRepository.save(token);
        
        // TODO send email and remove debug from the next line
        return new ObjectMapper().createObjectNode().put("status", "sent").put("debug", publicToken);
    }
    
    /**
     * @api {post} /reset-password Reset user password
     * @apiGroup User
     * 
     * @apiParam {String} email
     * @apiParam {String} token
     * @apiParam {String} newPassword
     *
     * @apiParamExample {json} Request-Example:
     *     {
     *       "email": "test@test.org",
     *       "token": "MTQ1ODQzNjA4OC4zNTE4ODEwYi0zNmQwLTQwNzItYTU0Ni02NTQwM2QwYTgwNTc=",
     *       "newPassword": "123456"
     *     }
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     */
    @POST
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public ObjectNode reset(@Valid ResetPasswordInput input) {
        String expires;
        String rawToken;
        
        try {
            String decodedPublicToken = new String(Base64.getDecoder().decode(input.getToken()));
            expires = decodedPublicToken.substring(0, decodedPublicToken.indexOf("."));
            rawToken = decodedPublicToken.substring(decodedPublicToken.indexOf(".") + 1);
        } catch (Throwable t) {
            throw new BadRequestException("Invalid token");
        }
        
        PasswordResetToken token = passwordResetTokenRepository.load(input.getEmail(), expires);
        
        if (token == null || !PasswordResetToken.checkToken(rawToken, token.getToken())) {
            throw new BadRequestException("Invalid token");
        }
        
        if (LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) > Long.valueOf(expires)) {
            throw new BadRequestException("This token is expired");
        }
        
        Email email = emailRepository.load(token.getEmail());

        if (!email.getUserguid().equals(token.getUserguid())) {
            throw new BadRequestException("Invalid token");
        }
        
        //TODO delete token
        email.setPassword(Email.encryptPassword(input.getNewPassword()));
        emailRepository.save(email);
        
        return new ObjectMapper().createObjectNode().put("status", "reset");
    }

    public static class RequestResetPasswordInput {
        @NotNull
        private String email;

        public String getEmail() {
            return email;
        }

        public void setEmail(String email) {
            this.email = email;
        }
    }
    
    public static class ResetPasswordInput {
        @NotNull
        private String email;
        
        @NotNull
        private String token;
        
        @NotEmpty
        @NotNull
        @Length(min = 6)
        private String newPassword;

        public String getEmail() {
            return email;
        }

        public void setEmail(String email) {
            this.email = email;
        }

        public String getToken() {
            return token;
        }

        public void setToken(String token) {
            this.token = token;
        }

        public String getNewPassword() {
            return newPassword;
        }

        public void setNewPassword(String newPassword) {
            this.newPassword = newPassword;
        }
    }
}
 @Path("/signup/email")
public class SignUpController {
    @Inject EmailRepository emailRepository;
    @Inject UserRepository userRepository;

    /**
     * @api {post} /signup/email Sign up
     * @apiGroup User
     * 
     * @apiParam {String} TODO
     *
     * @apiParamExample {json} Request-Example:
     *     {
     *       "email": "test@test.org",
     *       "firstname": "Rogério",
     *       "lastname": "Yokomizo",
     *       "password": "123456"
     *     }
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     *
     * @apiSuccessExample Success-Response:
     *     {
     *       "guid": "ffcec387-81fe-4e8e-985e-4025a65b036e",
     *       "email": "test@test.org",
     *       "firstname": "Rogério",
     *       "lastname": "Yokomizo",
     *       "location": null,
     *       "facebookurl": null,
     *       "twitter": null,
     *       "profilepictureguid": null
     *     }
     */
    @POST
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public User signUp(@Valid SignUpInput input) {
        if (emailRepository.load(input.getEmail()) != null) {
            throw new BadRequestException("Email already registered");
        }
        
        final String guid = UUID.randomUUID().toString();
        
        User user = new User();
        user.setGuid(guid);
        user.setFirstname(input.getFirstname());
        user.setLastname(input.getLastname());
        user.setEmail(input.getEmail());
        
        Email email = new Email();
        email.setUserguid(guid);
        email.setEmail(input.getEmail());
        email.setPassword(Email.encryptPassword(input.getPassword()));
        
        //TODO made it asynchronous
        emailRepository.save(email);
        userRepository.save(user);
        
        return user;
    }

    public static class SignUpInput {
        @NotNull
        @org.hibernate.validator.constraints.Email
        private String email;
        
        @NotNull
        @NotEmpty
        private String firstname;
        
        private String lastname;
        
        @NotEmpty
        @NotNull
        @Length(min = 6)
        private String password;
        
        public String getEmail() {
            return email;
        }
        
        public void setEmail(String email) {
            this.email = email;
        }
        
        public String getFirstname() {
            return firstname;
        }
        
        public void setFirstname(String firstname) {
            this.firstname = firstname;
        }
        
        public String getLastname() {
            return lastname;
        }
        
        public void setLastname(String lastname) {
            this.lastname = lastname;
        }
        
        public String getPassword() {
            return password;
        }
        
        public void setPassword(String password) {
            this.password = password;
        }
    }
}
 @Path("/thumbsup")
public class ThumbsUpController {
    @Inject
    ThumbsUpRepository thumbsUpRepository;
    @Inject
    FocusRepository focusRepository;
    @Inject
    FocusIndexer focusIndexer;
    @Inject
    User currentUser;

    /**
     * @api {post} /thumbsup Thumbs up
     * @apiGroup Focus
     * 
     * @apiParam {String} TODO
     *
     * @apiParamExample {json} Request-Example:
     *     {
     *       "focusguid": "a92ea2d2-6d7f-49ac-bdd4-61660f703406"
     *     }
     * 
     * @apiSuccessExample Success-Headers:
     *     HTTP/1.1 200 OK
     *
     * @apiSuccessExample Success-Response:
     *     {
     *       "thumbsup": 1
     *     }
     */
    @POST
    @Consumes("application/json")
    @Produces("application/json;charset=UTF-8")
    public ObjectNode thumbsUp(@Valid ThumbsUpPostInput input) {
        if (thumbsUpRepository.load(input.getFocusguid(), currentUser.getGuid()) != null) {
            throw new BadRequestException("User has already voted on this");
        }

        Focus focus = focusRepository.loadOrNotFound(input.getFocusguid()).thumbsup();

        ThumbsUp thumbsUp = new ThumbsUp();
        thumbsUp.setFocusguid(input.getFocusguid());
        thumbsUp.setUserguid(currentUser.getGuid());

        thumbsUpRepository.save(thumbsUp);
        focusRepository.save(focus);
        focusIndexer.index(focus); //TODO make it asynchronous

        return new ObjectMapper().createObjectNode().put("thumbsup", focus.getThumbsup());
    }

    public static class ThumbsUpPostInput {
        @NotNull
        private String focusguid;

        public String getFocusguid() {
            return focusguid;
        }

        public void setFocusguid(String focusguid) {
            this.focusguid = focusguid;
        }
    }
}
 public class BadRequestExceptionMapper implements ExceptionMapper<BadRequestException> {
    @Override
    public Response toResponse(BadRequestException exception) {
        ObjectNode error = new ObjectMapper().createObjectNode();
        error.put("status", "error");
        error.put("message", exception.getMessage());
        
        return Response.status(Status.BAD_REQUEST).entity(error).type("application/json;charset=UTF-8").build();
    }
}
 public class ForbiddenExceptionMapper implements ExceptionMapper<ForbiddenException> {
    @Override
    public Response toResponse(ForbiddenException exception) {
        ObjectNode error = new ObjectMapper().createObjectNode();
        error.put("status", "error");
        error.put("message", exception.getMessage());
        
        return Response.status(Status.FORBIDDEN).entity(error).type("application/json;charset=UTF-8").build();
    }
}
 public class InternalServerErrorExceptionMapper implements ExceptionMapper<Throwable> {
    @Override
    public Response toResponse(Throwable exception) {
        exception.printStackTrace();
        
        ObjectNode error = new ObjectMapper().createObjectNode();
        error.put("status", "error");
        error.put("message", "Internal server error");
        
        return Response.status(Status.INTERNAL_SERVER_ERROR).entity(error).type("application/json;charset=UTF-8")
                .build();
    }
}
 public class JsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException> {

    @Override
    public Response toResponse(JsonMappingException exception) {
        ObjectNode error = new ObjectMapper().createObjectNode();
        error.put("status", "error");
        error.put("message", "Error mapping json");

        return Response.status(Status.BAD_REQUEST).entity(error).type("application/json;charset=UTF-8").build();
    }

}
 public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {

    @Override
    public Response toResponse(JsonParseException arg0) {
        ObjectNode error = new ObjectMapper().createObjectNode();
        error.put("status", "error");
        error.put("message", "Invalid json");

        return Response.status(Status.BAD_REQUEST).entity(error).type("application/json;charset=UTF-8").build();
    }

}
 public class NotFoundExceptionMapper implements ExceptionMapper<NotFoundException> {
    @Override
    public Response toResponse(NotFoundException exception) {
        String response = "{\"status\": \"error\", \"message\": \"Not found\"}";
        
        return Response.status(Status.NOT_FOUND).entity(response).type("application/json;charset=UTF-8").build();
    }
}
 public class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {

    @Override
    public Response toResponse(ValidationException exception) {
        ObjectNode error = new ObjectMapper().createObjectNode();
        error.put("status", "error");
        error.put("message", "Missing parameters");

        return Response.status(Status.BAD_REQUEST).entity(error).type("application/json;charset=UTF-8").build();
    }

}
 public class FactoryBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bindFactory(AmazonCloudSearchFactory.class).to(AmazonCloudSearch.class).in(Singleton.class);
        bindFactory(AmazonDynamoDBFactory.class).to(AmazonDynamoDB.class).in(Singleton.class);
        bindFactory(AmazonS3ClientFactory.class).to(AmazonS3Client.class).in(Singleton.class);
        bindFactory(AWSCredentialsProviderFactory.class).to(AWSCredentialsProvider.class).in(Singleton.class);
        bindFactory(CurrentUserFactory.class).to(User.class).in(RequestScoped.class);
        bindFactory(DynamoDBConfigurationFactory.class).to(ClientConfiguration.class).in(Singleton.class);
        bindFactory(DynamoDBFactory.class).to(DynamoDB.class).in(Singleton.class);
        bindFactory(DynamoDBMapperFactory.class).to(DynamoDBMapper.class).in(Singleton.class);
        bindFactory(EnvFactory.class).to(Env.class).in(Singleton.class);
        bindFactory(ExecutorServiceFactory.class).to(ExecutorService.class).in(Singleton.class);
        bindFactory(ObjectMapperFactory.class).to(ObjectMapper.class).in(Singleton.class);
        bindFactory(WebRequestorFactory.class).to(WebRequestor.class).in(Singleton.class);
    }
}
 public class CORSFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext request, ContainerResponseContext response) throws IOException {
        response.getHeaders().add("Access-Control-Allow-Origin", "*");
        response.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
        response.getHeaders().add("Access-Control-Allow-Credentials", "true");
        response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
    }
} public class IndexerBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(FocusIndexer.class).to(FocusIndexer.class).in(Singleton.class);
    }
} public class RepositoryBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(EmailRepository.class).to(EmailRepository.class);
        bind(FacebookUserRepository.class).to(FacebookUserRepository.class);
        bind(FocusRepository.class).to(FocusRepository.class);
        bind(PasswordResetTokenRepository.class).to(PasswordResetTokenRepository.class);
        bind(PictureRepository.class).to(PictureRepository.class);
        bind(ThumbsUpRepository.class).to(ThumbsUpRepository.class);
        bind(UserRepository.class).to(UserRepository.class);
    }
}
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import com.coding4people.mosquitoreport.api.auth.AuthenticationBinder;
import com.coding4people.mosquitoreport.api.buckets.BucketBinder;
import com.coding4people.mosquitoreport.api.controllers.AuthEmailController;
import com.coding4people.mosquitoreport.api.controllers.AuthFacebookController;
import com.coding4people.mosquitoreport.api.controllers.FocusController;
import com.coding4people.mosquitoreport.api.controllers.HealthCheckController;
import com.coding4people.mosquitoreport.api.controllers.PictureController;
import com.coding4people.mosquitoreport.api.controllers.PostFocusController;
import com.coding4people.mosquitoreport.api.controllers.ProfileController;
import com.coding4people.mosquitoreport.api.controllers.ResetPasswordController;
import com.coding4people.mosquitoreport.api.controllers.SignUpController;
import com.coding4people.mosquitoreport.api.controllers.ThumbsUpController;
import com.coding4people.mosquitoreport.api.exceptionmappers.BadRequestExceptionMapper;
import com.coding4people.mosquitoreport.api.exceptionmappers.ForbiddenExceptionMapper;
import com.coding4people.mosquitoreport.api.exceptionmappers.InternalServerErrorExceptionMapper;
import com.coding4people.mosquitoreport.api.exceptionmappers.JsonMappingExceptionMapper;
import com.coding4people.mosquitoreport.api.exceptionmappers.JsonParseExceptionMapper;
import com.coding4people.mosquitoreport.api.exceptionmappers.NotFoundExceptionMapper;
import com.coding4people.mosquitoreport.api.exceptionmappers.ValidationExceptionMapper;
import com.coding4people.mosquitoreport.api.factories.FactoryBinder;
import com.coding4people.mosquitoreport.api.filters.CORSFilter;
import com.coding4people.mosquitoreport.api.indexers.IndexerBinder;
import com.coding4people.mosquitoreport.api.repositories.RepositoryBinder;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
package com.coding4people.mosquitoreport.api;




public class Config extends ResourceConfig {
    public Config configureControllers() {
        register(AuthEmailController.class);
        register(AuthFacebookController.class);
        register(FocusController.class);
        register(HealthCheckController.class);
        register(PictureController.class);
        register(PostFocusController.class);