Added content model entities.
This commit is contained in:
parent
8ace7399ca
commit
be880e312f
|
@ -31,3 +31,6 @@ build/
|
||||||
|
|
||||||
### VS Code ###
|
### VS Code ###
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
|
*.mv.db
|
||||||
|
*.db
|
||||||
|
|
|
@ -19,4 +19,4 @@ Therefore, you can think of onyx as a more robust, secure digital drive for your
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
||||||
Because each onyx node operates independently, there is no central authentication service, but instead each node maintains a set of users, and issues short-lived tokens granting users access to secure resources. When a user needs to access resources from a networked onyx node, their home node will send the user's id and the home node's own thing.
|
Because each onyx node operates independently, there is no central authentication service, but instead each node maintains a set of users, and issues short-lived tokens granting users access to secure resources. When a user needs to access resources from a networked onyx node, they'll use their own token, which the networked node will independently verify was issued recently by the user's home node.
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.andrewlalis.onyx.content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The different levels of access that can be set for content in an onyx node.
|
||||||
|
*/
|
||||||
|
public enum ContentAccessLevel {
|
||||||
|
/**
|
||||||
|
* An access level that does not permit reading or editing the content.
|
||||||
|
*/
|
||||||
|
NONE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An access level that permits reading content, but not editing.
|
||||||
|
*/
|
||||||
|
VIEW,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An access level that permits reading and editing content.
|
||||||
|
*/
|
||||||
|
EDIT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An access level that takes the parent node's access level.
|
||||||
|
*/
|
||||||
|
INHERIT
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.andrewlalis.onyx.content;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity meant to be attached to a {@link ContentNode}, which contains the
|
||||||
|
* access levels for the different ways in which a content node can be accessed.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "content_access_rules")
|
||||||
|
@Getter
|
||||||
|
public class ContentAccessRules {
|
||||||
|
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content node that these access rules apply to.
|
||||||
|
*/
|
||||||
|
@OneToOne(mappedBy = "accessInfo", fetch = FetchType.LAZY)
|
||||||
|
private ContentNode contentNode;
|
||||||
|
|
||||||
|
/** The access level that applies to users from outside this onyx network. */
|
||||||
|
@Enumerated(EnumType.ORDINAL) @Column(nullable = false, columnDefinition = "TINYINT NOT NULL")
|
||||||
|
private ContentAccessLevel publicAccessLevel = ContentAccessLevel.INHERIT;
|
||||||
|
|
||||||
|
/** The access level that applies to users from within this onyx network. */
|
||||||
|
@Enumerated(EnumType.ORDINAL) @Column(nullable = false, columnDefinition = "TINYINT NOT NULL")
|
||||||
|
private ContentAccessLevel networkAccessLevel = ContentAccessLevel.INHERIT;
|
||||||
|
|
||||||
|
/** The access level that applies to users within only this onyx node. */
|
||||||
|
@Enumerated(EnumType.ORDINAL) @Column(nullable = false, columnDefinition = "TINYINT NOT NULL")
|
||||||
|
private ContentAccessLevel nodeAccessLevel = ContentAccessLevel.INHERIT;
|
||||||
|
|
||||||
|
// TODO: Add a user allowlist.
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.andrewlalis.onyx.content;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type of content node that contains a list of children, which could
|
||||||
|
* themselves be any type of content node.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "content_node_container")
|
||||||
|
public final class ContentContainerNode extends ContentNode {
|
||||||
|
/**
|
||||||
|
* The set of children that belong to this container.
|
||||||
|
*/
|
||||||
|
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "parentContainer")
|
||||||
|
private Set<ContentNode> children;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.andrewlalis.onyx.content;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Lob;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type of content node that contains a single document.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "content_node_document")
|
||||||
|
public class ContentDocumentNode extends ContentNode {
|
||||||
|
@Column(nullable = false, updatable = false, length = 127)
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw file content for this document.
|
||||||
|
*/
|
||||||
|
@Lob @Column(nullable = false)
|
||||||
|
private byte[] content;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package com.andrewlalis.onyx.content;
|
||||||
|
|
||||||
|
import com.andrewlalis.onyx.content.history.ContentNodeHistory;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The abstract model that represents all nodes in the system's hierarchical
|
||||||
|
* content tree, including both <em>containers</em> and <em>documents</em>.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "content_node")
|
||||||
|
@Inheritance(strategy = InheritanceType.JOINED)
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
public abstract class ContentNode {
|
||||||
|
public static final int MAX_NAME_LENGTH = 127;
|
||||||
|
|
||||||
|
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = MAX_NAME_LENGTH)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.ORDINAL) @Column(columnDefinition = "TINYINT NOT NULL")
|
||||||
|
private Type type;
|
||||||
|
|
||||||
|
@OneToOne(fetch = FetchType.LAZY, optional = false, orphanRemoval = true, cascade = CascadeType.ALL)
|
||||||
|
private ContentAccessRules accessInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The container node that this one belongs to. This will be null <strong>only</strong>
|
||||||
|
* in the case of the root node, which is a special, hidden container node
|
||||||
|
* that acts as the top-level of the content hierarchy.
|
||||||
|
*/
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
private ContentContainerNode parentContainer;
|
||||||
|
|
||||||
|
@OneToOne(fetch = FetchType.LAZY, optional = false, orphanRemoval = true, cascade = CascadeType.ALL)
|
||||||
|
private ContentNodeHistory history;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private boolean archived;
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
CONTAINER,
|
||||||
|
DOCUMENT
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentNode(String name, Type type, ContentContainerNode parentContainer) {
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.parentContainer = parentContainer;
|
||||||
|
this.history = new ContentNodeHistory(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.andrewlalis.onyx.content.history;
|
||||||
|
|
||||||
|
import com.andrewlalis.onyx.content.ContentNode;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity that represents the complete history of a single content node,
|
||||||
|
* storing an ordered list of entries detailing how that node has changed.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "content_node_history")
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
public class ContentNodeHistory {
|
||||||
|
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@OneToOne(mappedBy = "history")
|
||||||
|
private ContentNode contentNode;
|
||||||
|
|
||||||
|
@CreationTimestamp
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "history")
|
||||||
|
private Set<ContentNodeHistoryEntry> entries;
|
||||||
|
|
||||||
|
public ContentNodeHistory(ContentNode contentNode) {
|
||||||
|
this.contentNode = contentNode;
|
||||||
|
this.entries = new HashSet<>();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.andrewlalis.onyx.content.history;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base class for all types of content node history entries. It defines
|
||||||
|
* some basic properties that all entries should have.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "content_node_history_entry")
|
||||||
|
@Inheritance(strategy = InheritanceType.JOINED)
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
public abstract class ContentNodeHistoryEntry {
|
||||||
|
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@CreationTimestamp
|
||||||
|
private LocalDateTime timestamp;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||||
|
private ContentNodeHistory history;
|
||||||
|
|
||||||
|
// TODO: Add user info (or system)
|
||||||
|
|
||||||
|
public ContentNodeHistoryEntry(ContentNodeHistory history) {
|
||||||
|
this.history = history;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.andrewlalis.onyx.content.history.entry;
|
||||||
|
|
||||||
|
import com.andrewlalis.onyx.content.ContentAccessLevel;
|
||||||
|
import com.andrewlalis.onyx.content.history.ContentNodeHistory;
|
||||||
|
import com.andrewlalis.onyx.content.history.ContentNodeHistoryEntry;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A history entry that records a modification to a content node's access rules
|
||||||
|
* by a user or the system.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "content_node_history_entry_access_rules")
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
public class AccessRulesEntry extends ContentNodeHistoryEntry {
|
||||||
|
@Enumerated(EnumType.ORDINAL) @Column(nullable = false, columnDefinition = "TINYINT NOT NULL")
|
||||||
|
private ContentAccessLevel oldPublicAccessLevel;
|
||||||
|
@Enumerated(EnumType.ORDINAL) @Column(nullable = false, columnDefinition = "TINYINT NOT NULL")
|
||||||
|
private ContentAccessLevel oldNetworkAccessLevel;
|
||||||
|
@Enumerated(EnumType.ORDINAL) @Column(nullable = false, columnDefinition = "TINYINT NOT NULL")
|
||||||
|
private ContentAccessLevel oldNodeAccessLevel;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.ORDINAL) @Column(nullable = false, columnDefinition = "TINYINT NOT NULL")
|
||||||
|
private ContentAccessLevel newPublicAccessLevel;
|
||||||
|
@Enumerated(EnumType.ORDINAL) @Column(nullable = false, columnDefinition = "TINYINT NOT NULL")
|
||||||
|
private ContentAccessLevel newNetworkAccessLevel;
|
||||||
|
@Enumerated(EnumType.ORDINAL) @Column(nullable = false, columnDefinition = "TINYINT NOT NULL")
|
||||||
|
private ContentAccessLevel newNodeAccessLevel;
|
||||||
|
|
||||||
|
// TODO: add usersAllowed, usersDisallowed
|
||||||
|
|
||||||
|
public AccessRulesEntry(
|
||||||
|
ContentNodeHistory history,
|
||||||
|
ContentAccessLevel oldPublicAccessLevel,
|
||||||
|
ContentAccessLevel oldNetworkAccessLevel,
|
||||||
|
ContentAccessLevel oldNodeAccessLevel,
|
||||||
|
ContentAccessLevel newPublicAccessLevel,
|
||||||
|
ContentAccessLevel newNetworkAccessLevel,
|
||||||
|
ContentAccessLevel newNodeAccessLevel
|
||||||
|
) {
|
||||||
|
super(history);
|
||||||
|
this.oldPublicAccessLevel = oldPublicAccessLevel;
|
||||||
|
this.oldNetworkAccessLevel = oldNetworkAccessLevel;
|
||||||
|
this.oldNodeAccessLevel = oldNodeAccessLevel;
|
||||||
|
this.newPublicAccessLevel = newPublicAccessLevel;
|
||||||
|
this.newNetworkAccessLevel = newNetworkAccessLevel;
|
||||||
|
this.newNodeAccessLevel = newNodeAccessLevel;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.andrewlalis.onyx.content.history.entry;
|
||||||
|
|
||||||
|
import com.andrewlalis.onyx.content.history.ContentNodeHistory;
|
||||||
|
import com.andrewlalis.onyx.content.history.ContentNodeHistoryEntry;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* History entry for tracking the state of a content node's `archived` status.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "content_node_history_entry_archived")
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
public class ArchivedEntry extends ContentNodeHistoryEntry {
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
private boolean archived;
|
||||||
|
|
||||||
|
public ArchivedEntry(ContentNodeHistory history, boolean archived) {
|
||||||
|
super(history);
|
||||||
|
this.archived = archived;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.andrewlalis.onyx.content.history.entry;
|
||||||
|
|
||||||
|
import com.andrewlalis.onyx.content.ContentNode;
|
||||||
|
import com.andrewlalis.onyx.content.history.ContentNodeHistory;
|
||||||
|
import com.andrewlalis.onyx.content.history.ContentNodeHistoryEntry;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* History entry for tracking updates to the contents of a container node.
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "content_node_history_entry_container_edit")
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
public class ContainerEditEntry extends ContentNodeHistoryEntry {
|
||||||
|
public enum EditType {
|
||||||
|
CONTAINER_ADDED,
|
||||||
|
CONTAINER_REMOVED,
|
||||||
|
DOCUMENT_ADDED,
|
||||||
|
DOCUMENT_REMOVED
|
||||||
|
}
|
||||||
|
|
||||||
|
@Enumerated(EnumType.ORDINAL)
|
||||||
|
private EditType type;
|
||||||
|
|
||||||
|
@Column(nullable = false, updatable = false, length = ContentNode.MAX_NAME_LENGTH)
|
||||||
|
private String affectedNodeName;
|
||||||
|
|
||||||
|
public ContainerEditEntry(ContentNodeHistory history, EditType type, String affectedNodeName) {
|
||||||
|
super(history);
|
||||||
|
this.type = type;
|
||||||
|
this.affectedNodeName = affectedNodeName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.andrewlalis.onyx.content.history.entry;
|
||||||
|
|
||||||
|
import com.andrewlalis.onyx.content.ContentNode;
|
||||||
|
import com.andrewlalis.onyx.content.history.ContentNodeHistory;
|
||||||
|
import com.andrewlalis.onyx.content.history.ContentNodeHistoryEntry;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "content_node_history_entry_rename")
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
public class RenameEntry extends ContentNodeHistoryEntry {
|
||||||
|
@Column(nullable = false, updatable = false, length = ContentNode.MAX_NAME_LENGTH)
|
||||||
|
private String oldName;
|
||||||
|
|
||||||
|
@Column(nullable = false, updatable = false, length = ContentNode.MAX_NAME_LENGTH)
|
||||||
|
private String newName;
|
||||||
|
|
||||||
|
public RenameEntry(ContentNodeHistory history, String oldName, String newName) {
|
||||||
|
super(history);
|
||||||
|
this.oldName = oldName;
|
||||||
|
this.newName = newName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
/**
|
||||||
|
* This package defines the <strong>content</strong> module for the onyx node,
|
||||||
|
* which is responsible for managing the actual hierarchical set of documents
|
||||||
|
* that are directly stored by the node.
|
||||||
|
*/
|
||||||
|
package com.andrewlalis.onyx.content;
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Development-specific settings.
|
||||||
|
|
||||||
|
spring.datasource.url=jdbc:h2:./onyx-db-dev
|
||||||
|
spring.datasource.driver-class-name=org.h2.Driver
|
||||||
|
spring.jpa.hibernate.ddl-auto=create
|
Loading…
Reference in New Issue