From da9f6bcc768e6e3f29ae45e811da8557acf5dcd4 Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Mon, 14 Mar 2022 22:33:57 +0100
Subject: [PATCH] WIP: fix #220

---
 .../java/org/caosdb/server/entity/Entity.java |   3 +-
 .../caosdb/server/entity/EntityInterface.java |   2 +
 .../server/entity/wrapper/EntityWrapper.java  |   5 +
 .../server/entity/xml/SetFieldStrategy.java   |   3 +-
 .../server/grpc/CaosDBToGrpcConverters.java   | 106 ++++++++++++------
 .../grpc/EntityTransactionServiceImpl.java    |  21 +++-
 6 files changed, 99 insertions(+), 41 deletions(-)

diff --git a/src/main/java/org/caosdb/server/entity/Entity.java b/src/main/java/org/caosdb/server/entity/Entity.java
index 3e49b08f..4550eebf 100644
--- a/src/main/java/org/caosdb/server/entity/Entity.java
+++ b/src/main/java/org/caosdb/server/entity/Entity.java
@@ -540,7 +540,8 @@ public class Entity extends AbstractObservable implements EntityInterface {
     return getToElementStrategy().toElement(this, getSerializeFieldStrategy());
   }
 
-  private SetFieldStrategy getSerializeFieldStrategy() {
+  @Override
+  public SetFieldStrategy getSerializeFieldStrategy() {
     if (this.serializeFieldStrategy == null) {
       this.serializeFieldStrategy = new SetFieldStrategy(getSelections());
     }
diff --git a/src/main/java/org/caosdb/server/entity/EntityInterface.java b/src/main/java/org/caosdb/server/entity/EntityInterface.java
index 46726df6..b26a4057 100644
--- a/src/main/java/org/caosdb/server/entity/EntityInterface.java
+++ b/src/main/java/org/caosdb/server/entity/EntityInterface.java
@@ -199,4 +199,6 @@ public interface EntityInterface
    * AbstractCollectionDatatype's elements' data type is an instance of ReferenceDatatype.
    */
   public abstract boolean isReferenceList();
+
+  public abstract SetFieldStrategy getSerializeFieldStrategy();
 }
diff --git a/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java b/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java
index 01c374ec..f8ccfa93 100644
--- a/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java
+++ b/src/main/java/org/caosdb/server/entity/wrapper/EntityWrapper.java
@@ -580,4 +580,9 @@ public class EntityWrapper implements EntityInterface {
   public void setSerializeFieldStrategy(SetFieldStrategy s) {
     this.entity.setSerializeFieldStrategy(s);
   }
+
+  @Override
+  public SetFieldStrategy getSerializeFieldStrategy() {
+    return this.entity.getSerializeFieldStrategy();
+  }
 }
diff --git a/src/main/java/org/caosdb/server/entity/xml/SetFieldStrategy.java b/src/main/java/org/caosdb/server/entity/xml/SetFieldStrategy.java
index 2d6b696c..a8587284 100644
--- a/src/main/java/org/caosdb/server/entity/xml/SetFieldStrategy.java
+++ b/src/main/java/org/caosdb/server/entity/xml/SetFieldStrategy.java
@@ -135,10 +135,11 @@ public class SetFieldStrategy {
 
     if (this.cache == null) {
       this.cache = new HashMap<String, Boolean>();
-      // always include the id, version and the name
+      // always include the id, version, role and the name
       this.cache.put("id", true);
       this.cache.put("version", true);
       this.cache.put("name", true);
+      this.cache.put("role", true);
 
       // ... and the referenced entity.
       this.cache.put("_referenced", true);
diff --git a/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java b/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java
index d9ac193c..97253fde 100644
--- a/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java
+++ b/src/main/java/org/caosdb/server/grpc/CaosDBToGrpcConverters.java
@@ -24,6 +24,7 @@ package org.caosdb.server.grpc;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.TimeZone;
 import org.caosdb.api.entity.v1.AtomicDataType;
 import org.caosdb.api.entity.v1.CollectionValues;
@@ -69,8 +70,8 @@ import org.caosdb.server.entity.Message;
 import org.caosdb.server.entity.Role;
 import org.caosdb.server.entity.StatementStatus;
 import org.caosdb.server.entity.container.ParentContainer;
-import org.caosdb.server.entity.container.PropertyContainer;
 import org.caosdb.server.entity.wrapper.Property;
+import org.caosdb.server.entity.xml.SetFieldStrategy;
 import org.caosdb.server.permissions.EntityACI;
 import org.caosdb.server.permissions.EntityPermission;
 
@@ -97,24 +98,25 @@ public class CaosDBToGrpcConverters {
 
   public EntityResponse.Builder convert(final EntityInterface from) {
 
+    SetFieldStrategy s = from.getSerializeFieldStrategy();
     final Builder entityBuilder = Entity.newBuilder();
 
-    if (from.hasId()) {
+    if (from.hasId() && s.isToBeSet("id")) {
       entityBuilder.setId(Integer.toString(from.getId()));
     }
-    if (from.getRole() != null) {
+    if (from.getRole() != null && s.isToBeSet("role")) {
       entityBuilder.setRole(convert(from.getRole()));
     }
-    if (from.hasName()) {
+    if (from.hasName() && s.isToBeSet("name")) {
       entityBuilder.setName(from.getName());
     }
-    if (from.hasDescription()) {
+    if (from.hasDescription() && s.isToBeSet("description")) {
       entityBuilder.setDescription(from.getDescription());
     }
-    if (from.hasDatatype()) {
+    if (from.hasDatatype() && s.isToBeSet("datatype")) {
       entityBuilder.setDataType(convert(from.getDatatype()));
     }
-    if (from.hasValue()) {
+    if (from.hasValue() && s.isToBeSet("value")) {
       try {
         from.parseValue();
       } catch (final Message e) {
@@ -125,17 +127,20 @@ public class CaosDBToGrpcConverters {
       entityBuilder.setValue(convert(from.getValue()));
     }
     final String unit = getStringUnit(from);
-    if (unit != null) {
+    if (unit != null && s.isToBeSet("unit")) {
       entityBuilder.setUnit(unit);
     }
     if (from.hasProperties()) {
-      entityBuilder.addAllProperties(convert(from.getProperties()));
+      entityBuilder.addAllProperties(convertProperties(from));
     }
-    if (from.hasParents()) {
+    if (from.hasParents() && s.isToBeSet("parent")) {
       entityBuilder.addAllParents(convert(from.getParents()));
     }
     if (from.hasFileProperties()) {
-      entityBuilder.setFileDescriptor(convert(from.getFileProperties()));
+      FileDescriptor.Builder fileDescriptor = convert(s, from.getFileProperties());
+      if (fileDescriptor != null) {
+        entityBuilder.setFileDescriptor(fileDescriptor);
+      }
     }
 
     final EntityResponse.Builder responseBuilder = EntityResponse.newBuilder();
@@ -146,10 +151,18 @@ public class CaosDBToGrpcConverters {
     return responseBuilder;
   }
 
-  private FileDescriptor.Builder convert(FileProperties fileProperties) {
-    FileDescriptor.Builder result = FileDescriptor.newBuilder();
-    result.setPath(fileProperties.getPath());
-    result.setSize(fileProperties.getSize());
+  private FileDescriptor.Builder convert(SetFieldStrategy s, FileProperties fileProperties) {
+    FileDescriptor.Builder result = null;
+    if (s.isToBeSet("path")) {
+      result = FileDescriptor.newBuilder();
+      result.setPath(fileProperties.getPath());
+    }
+    if (s.isToBeSet("size")) {
+      if (result == null) {
+        result = FileDescriptor.newBuilder();
+      }
+      result.setSize(fileProperties.getSize());
+    }
     return result;
   }
 
@@ -216,23 +229,24 @@ public class CaosDBToGrpcConverters {
     final org.caosdb.api.entity.v1.Property.Builder builder =
         org.caosdb.api.entity.v1.Property.newBuilder();
 
-    if (from.hasId()) {
+    SetFieldStrategy s = from.getSerializeFieldStrategy();
+    if (from.hasId() && s.isToBeSet("id")) {
       builder.setId(from.getId().toString());
     }
-    if (from.hasName()) {
+    if (from.hasName() && s.isToBeSet("name")) {
       builder.setName(from.getName());
     }
-    if (from.hasDescription()) {
+    if (from.hasDescription() && s.isToBeSet("description")) {
       builder.setDescription(from.getDescription());
     }
-    if (from.hasDatatype()) {
+    if (from.hasDatatype() && s.isToBeSet("datatype")) {
       builder.setDataType(convert(from.getDatatype()));
     }
     final String unit = getStringUnit(from);
-    if (unit != null) {
+    if (unit != null && s.isToBeSet("unit")) {
       builder.setUnit(unit);
     }
-    if (from.hasValue()) {
+    if (from.hasValue() && s.isToBeSet("value")) {
       try {
         from.parseValue();
       } catch (final Message e) {
@@ -242,7 +256,9 @@ public class CaosDBToGrpcConverters {
       }
       builder.setValue(convert(from.getValue()));
     }
-    builder.setImportance(convert(from.getStatementStatus()));
+    if (s.isToBeSet("importance")) {
+      builder.setImportance(convert(from.getStatementStatus()));
+    }
     return builder.build();
   }
 
@@ -429,20 +445,42 @@ public class CaosDBToGrpcConverters {
     return ReferenceDataType.newBuilder().setName(datatype.getName());
   }
 
-  public Iterable<? extends org.caosdb.api.entity.v1.Property> convert(
-      final PropertyContainer from) {
-    final Iterator<org.caosdb.server.entity.wrapper.Property> iterator = from.iterator();
+  public Iterable<? extends org.caosdb.api.entity.v1.Property> convertProperties(
+      final EntityInterface from) {
+
+    final Iterator<org.caosdb.server.entity.wrapper.Property> iterator =
+        from.getProperties().iterator();
     return () ->
         new Iterator<>() {
 
+          private Property property;
+
           @Override
           public boolean hasNext() {
-            return iterator.hasNext();
+            while (iterator.hasNext()) {
+              this.property = iterator.next();
+              if (from.getSerializeFieldStrategy().isToBeSet(this.property.getName())) {
+                this.property.setSerializeFieldStrategy(
+                    from.getSerializeFieldStrategy().forProperty(this.property));
+                return true;
+              }
+            }
+            return false;
           }
 
           @Override
           public org.caosdb.api.entity.v1.Property next() {
-            return convert(iterator.next());
+            if (this.property == null) {
+              // trigger this.property to be non-null
+              if (!hasNext()) {
+                throw new NoSuchElementException("The iterator has no more elements.");
+              }
+            }
+
+            Property next_property = this.property;
+            this.property = null;
+
+            return convert(next_property);
           }
         };
   }
@@ -466,26 +504,28 @@ public class CaosDBToGrpcConverters {
 
   public void appendMessages(
       final EntityInterface from, final org.caosdb.api.entity.v1.EntityResponse.Builder builder) {
-    if (from.hasMessage(Message.MessageType.Error.toString())) {
+    SetFieldStrategy s = from.getSerializeFieldStrategy();
+    if (from.hasMessage(Message.MessageType.Error.toString()) && s.isToBeSet("error")) {
       builder.addAllErrors(convert(from.getMessages(Message.MessageType.Error.toString())));
     }
-    if (from.hasMessage(Message.MessageType.Warning.toString())) {
+    if (from.hasMessage(Message.MessageType.Warning.toString()) && s.isToBeSet("warning")) {
       builder.addAllWarnings(convert(from.getMessages(Message.MessageType.Warning.toString())));
     }
-    if (from.hasMessage(Message.MessageType.Info.toString())) {
+    if (from.hasMessage(Message.MessageType.Info.toString()) && s.isToBeSet("info")) {
       builder.addAllInfos(convert(from.getMessages(Message.MessageType.Info.toString())));
     }
   }
 
   public void appendMessages(
       final EntityInterface from, final org.caosdb.api.entity.v1.IdResponse.Builder builder) {
-    if (from.hasMessage(Message.MessageType.Error.toString())) {
+    SetFieldStrategy s = from.getSerializeFieldStrategy();
+    if (from.hasMessage(Message.MessageType.Error.toString()) && s.isToBeSet("error")) {
       builder.addAllErrors(convert(from.getMessages(Message.MessageType.Error.toString())));
     }
-    if (from.hasMessage(Message.MessageType.Warning.toString())) {
+    if (from.hasMessage(Message.MessageType.Warning.toString()) && s.isToBeSet("warning")) {
       builder.addAllWarnings(convert(from.getMessages(Message.MessageType.Warning.toString())));
     }
-    if (from.hasMessage(Message.MessageType.Info.toString())) {
+    if (from.hasMessage(Message.MessageType.Info.toString()) && s.isToBeSet("info")) {
       builder.addAllInfos(convert(from.getMessages(Message.MessageType.Info.toString())));
     }
   }
diff --git a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
index c234e610..f3f17794 100644
--- a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
+++ b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
@@ -26,6 +26,7 @@ import java.util.HashMap;
 import java.util.TimeZone;
 import java.util.UUID;
 import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
 import org.caosdb.api.entity.v1.DeleteRequest;
 import org.caosdb.api.entity.v1.DeleteResponse;
 import org.caosdb.api.entity.v1.Entity;
@@ -52,10 +53,12 @@ import org.caosdb.server.entity.DeleteEntity;
 import org.caosdb.server.entity.EntityInterface;
 import org.caosdb.server.entity.FileProperties;
 import org.caosdb.server.entity.InsertEntity;
+import org.caosdb.server.entity.Message;
 import org.caosdb.server.entity.RetrieveEntity;
 import org.caosdb.server.entity.UpdateEntity;
 import org.caosdb.server.entity.container.RetrieveContainer;
 import org.caosdb.server.entity.container.WritableContainer;
+import org.caosdb.server.permissions.EntityPermission;
 import org.caosdb.server.transaction.Retrieve;
 import org.caosdb.server.transaction.RetrieveACL;
 import org.caosdb.server.transaction.UpdateACL;
@@ -136,13 +139,19 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
         final EntityResponse.Builder entityResponse = caosdbToGrpc.convert(entity);
         if ((download_files_container || entity.getFlags().containsKey("download_files"))
             && entity.hasFileProperties()) {
-          if (fileDownload == null) {
-            fileDownload = fileTransmissionService.registerFileDownload(null);
+          try {
+            entity.checkPermission(EntityPermission.RETRIEVE_FILE);
+            if (fileDownload == null) {
+              fileDownload = fileTransmissionService.registerFileDownload(null);
+            }
+            entity.getFileProperties().retrieveFromFileSystem();
+            entityResponse.setDownloadId(
+                fileTransmissionService.registerFileDownload(
+                    fileDownload.getId(), entity.getFileProperties()));
+          } catch (AuthenticationException exc) {
+            entityResponse.addErrors(caosdbToGrpc.convert(ServerMessages.AUTHORIZATION_ERROR));
+            entityResponse.addInfos(caosdbToGrpc.convert(new Message(exc.getMessage())));
           }
-          entity.getFileProperties().retrieveFromFileSystem();
-          entityResponse.setDownloadId(
-              fileTransmissionService.registerFileDownload(
-                  fileDownload.getId(), entity.getFileProperties()));
         }
         builder
             .addResponsesBuilder()
-- 
GitLab