package org.karmaexchange.dao; import static org.karmaexchange.util.OfyService.ofy; import static org.karmaexchange.util.UserService.getCurrentUserKey; import java.util.Date; import javax.xml.bind.annotation.XmlRootElement; import org.karmaexchange.task.DeleteBlobServlet; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.ToString; import com.google.appengine.api.blobstore.BlobKey; import com.google.appengine.api.images.ImagesServiceFactory; import com.google.appengine.api.images.ServingUrlOptions; import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.Index; @XmlRootElement @Entity @Data @NoArgsConstructor @EqualsAndHashCode(callSuper=true) @ToString(callSuper=true) public class Image extends IdBaseDao<Image> { private BlobKey blobKey; private String url; private ImageProviderType urlProvider; @Index private Date dateUploaded; private String caption; private GeoPtWrapper gpsLocation; // Most images are tagged with gps information automatically. public static Image createAndPersist(Key<?> owner, BlobKey blobKey, String caption) { ServingUrlOptions options = ServingUrlOptions.Builder.withBlobKey(blobKey).secureUrl(true); // This call might be slow. This may have to be punted to a task queue. String url = ImagesServiceFactory.getImagesService().getServingUrl(options); Image image = new Image(owner, url, blobKey, caption); BaseDao.upsert(image); return image; } public static Image createAndPersist(Key<?> owner, ImageProviderType imageProviderType, String url) { Image image = new Image(owner, url, imageProviderType); BaseDao.upsert(image); return image; } private Image(Key<?> owner, String url, ImageProviderType urlProvider) { this.owner = owner; this.url = url; this.urlProvider = urlProvider; } private Image(Key<?> owner, String url, BlobKey blobKey, String caption) { this.owner = owner; this.blobKey = blobKey; this.url = url; urlProvider = ImageProviderType.BLOBSTORE; this.caption = caption; } @Override protected void preProcessInsert() { super.preProcessInsert(); this.dateUploaded = getModificationInfo().getCreationDate(); } @Override protected void processUpdate(Image prevObj) { super.processUpdate(prevObj); // Some fields can not be modified. blobKey = prevObj.blobKey; url = prevObj.url; urlProvider = prevObj.urlProvider; dateUploaded = prevObj.dateUploaded; } @Override protected void processDelete() { if (urlProvider == ImageProviderType.BLOBSTORE) { // We do this via a task queue so that it is transactionally done. Only if the transaction // that contains this commits will this task queue task be executed. DeleteBlobServlet.enqueueTask(blobKey); } } public String getBlobKey() { return (blobKey == null) ? null : blobKey.getKeyString(); } public void setBlobKey(String blobKeyStr) { blobKey = (blobKeyStr == null) ? null : new BlobKey(blobKeyStr); } @Override protected Permission evalPermission() { // TODO(avaliani): fill this in. Organizers of events should have // the ability to delete pictures also if the picture is owned by an // event. // This first check is required to handle bootstrapping of user profile images. // TODO(avaliani): re-eval in the future. if (owner.equals(getCurrentUserKey())) { return Permission.ALL; } else { BaseDao<?> ownerDao = (BaseDao<?>) ofy().load().key(owner).now(); return ownerDao.getPermission(); } } }