📄 LibraryRegistryStorage.sol
D-OPEN SOVEREIGN
1/*
2 * Copyright (c) 2026 DataPond D-Library Pty Ltd. ("The Sanctuary")
3 * Non-Profit Public Library — The World Library
4 *
5 * D-SAFE Certification issued by POND Enterprise.
6 * Published under the D-Open Code Sovereign Licence v1.0 framework
7 * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.
8 * https://registry.world.bibliotech.com/licence
9 * Source code donated to DataPond D-Library by it's author: data pond.
10 *
11 * Technical Guardian ("The Shield"): Pond Enterprise Pty Ltd. (ACN 694 747 987)
12 * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.
13 * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.
14 */
15
16// SPDX-License-Identifier: Apache-2.0
17pragma solidity ^0.8.24;
18
19import {ErrorLibrary} from "./ErrorLibrary.sol";
20
21interface IPublicLibraryStorage {
22 function libraryExists(uint256 id) external view returns (bool);
23}
24
25contract LibraryRegistryStorage {
26
27 enum LibraryType {
28 Online,
29 PhysicalWithDigitalCopies
30 }
31
32 enum ImportStatus {
33 Pending,
34 InProgress,
35 Completed,
36 Failed
37 }
38
39 struct Collection {
40 string id;
41 string slug;
42 string manifestUrl;
43 string importerUsername;
44 address owner;
45 bool verified;
46 uint256 fileCount;
47 LibraryType libraryType;
48 uint256 publicLibraryId; // 0 = not linked to a PublicLibraryStorage entry
49 string language;
50 bool isPublic;
51 uint64 createdAt;
52 uint64 updatedAt;
53 uint256 initialBookCount;
54 uint256 dSafeBookCount;
55 ImportStatus importStatus;
56 bool published;
57 }
58
59 struct CollectionInput {
60 string id;
61 string slug;
62 string manifestUrl;
63 string importerUsername;
64 address owner;
65 uint256 fileCount;
66 LibraryType libraryType;
67 uint256 publicLibraryId; // 0 = not linked to a PublicLibraryStorage entry
68 string language;
69 bool isPublic;
70 uint256 initialBookCount;
71 uint256 dSafeBookCount;
72 }
73
74 // State Variables
75 address public admin; // single admin or multi-sig if you choose
76 mapping(address => bool) public _isAuthorized; // reserved for future write access (unused for now)
77 IPublicLibraryStorage public publicLibraryStorage;
78
79 // Collection Storage
80 mapping(string => Collection) private collections;
81
82 string[] private unverifiedCollectionIds;
83 string[] private verifiedCollectionIds;
84
85 event AuthorizedAdded(address indexed caller);
86 event AuthorizedRemoved(address indexed caller);
87
88 // Modifiers
89 modifier onlyAdmin() {
90 require(msg.sender == admin, "not admin");
91 _;
92 }
93
94 modifier onlyAuthorized() {
95 require(_isAuthorized[msg.sender], "not authorized");
96 _;
97 }
98
99 constructor() {
100 admin = msg.sender;
101 }
102
103 // ===== Admin / authorization (reserved for future write access) =====
104 function isAuthorized(address caller) public view returns (bool) {
105 require(caller != address(0), "zero addr");
106 return _isAuthorized[caller];
107 }
108
109 function addAuthorized(address caller) public onlyAdmin {
110 require(caller != address(0), "zero addr");
111 _isAuthorized[caller] = true;
112 emit AuthorizedAdded(caller);
113 }
114
115 function removeAuthorized(address caller) public onlyAdmin {
116 _isAuthorized[caller] = false;
117 emit AuthorizedRemoved(caller);
118 }
119
120 function setPublicLibraryStorage(address storageAddr) external onlyAdmin {
121 if (storageAddr == address(0)) revert ErrorLibrary.EmptyAddress();
122 publicLibraryStorage = IPublicLibraryStorage(storageAddr);
123 }
124
125 // 0 means "not linked" and is always allowed; a non-zero id must exist in PublicLibraryStorage.
126 function _validatePublicLibraryId(uint256 publicLibraryId) internal view {
127 if (publicLibraryId == 0) return;
128 if (address(publicLibraryStorage) == address(0) || !publicLibraryStorage.libraryExists(publicLibraryId)) {
129 revert ErrorLibrary.InvalidPublicLibraryId();
130 }
131 }
132
133 // Public Submission — admin-only for now (Called by Orchestrator on Arweave Upload Success)
134 function addUnverifiedCollection(CollectionInput calldata input) external onlyAdmin {
135 if (bytes(collections[input.id].id).length != 0) {
136 revert ErrorLibrary.ErrAlreadyRegistered();
137 }
138 _validatePublicLibraryId(input.publicLibraryId);
139
140 uint64 nowTs = uint64(block.timestamp);
141
142 collections[input.id] = Collection({
143 id: input.id,
144 slug: input.slug,
145 manifestUrl: input.manifestUrl,
146 importerUsername: input.importerUsername,
147 owner: input.owner,
148 verified: false,
149 fileCount: input.fileCount,
150 libraryType: input.libraryType,
151 publicLibraryId: input.publicLibraryId,
152 language: input.language,
153 isPublic: input.isPublic,
154 createdAt: nowTs,
155 updatedAt: nowTs,
156 initialBookCount: input.initialBookCount,
157 dSafeBookCount: input.dSafeBookCount,
158 importStatus: ImportStatus.Pending,
159 published: false
160 });
161
162 unverifiedCollectionIds.push(input.id);
163 }
164
165 // Admin-only Read Operations (Access Control Restricted)
166 function getUnverifiedCollectionIds() external view onlyAdmin returns (string[] memory) {
167 return unverifiedCollectionIds;
168 }
169
170 // Public Read Operations
171 function getVerifiedCollectionIds() external view returns (string[] memory) {
172 return verifiedCollectionIds;
173 }
174
175 function getCollection(string calldata _id) external view returns (Collection memory) {
176 Collection memory c = collections[_id];
177 // Enforce that unverified collections are only viewable by the admin or the owner
178 if (!c.verified && msg.sender != admin && c.owner != msg.sender) {
179 revert ErrorLibrary.Forbidden(msg.sender);
180 }
181 return c;
182 }
183
184 // Manual Verification Workflow (admin-only for now)
185 function verifyCollection(string calldata _id) external onlyAdmin {
186 Collection storage c = collections[_id];
187 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
188 if (c.verified) revert ErrorLibrary.ErrAlreadyRegistered();
189
190 c.verified = true;
191 c.updatedAt = uint64(block.timestamp);
192 verifiedCollectionIds.push(_id);
193
194 // Remove from unverified list
195 for (uint256 i = 0; i < unverifiedCollectionIds.length; i++) {
196 if (keccak256(bytes(unverifiedCollectionIds[i])) == keccak256(bytes(_id))) {
197 unverifiedCollectionIds[i] = unverifiedCollectionIds[unverifiedCollectionIds.length - 1];
198 unverifiedCollectionIds.pop();
199 break;
200 }
201 }
202 }
203
204 function rejectCollection(string calldata _id) external onlyAdmin {
205 Collection memory c = collections[_id];
206 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
207 if (c.verified) revert ErrorLibrary.ErrAlreadyRegistered();
208
209 delete collections[_id];
210
211 // Remove from unverified list
212 for (uint256 i = 0; i < unverifiedCollectionIds.length; i++) {
213 if (keccak256(bytes(unverifiedCollectionIds[i])) == keccak256(bytes(_id))) {
214 unverifiedCollectionIds[i] = unverifiedCollectionIds[unverifiedCollectionIds.length - 1];
215 unverifiedCollectionIds.pop();
216 break;
217 }
218 }
219 }
220
221 // ===== Lifecycle updates (admin-only for now) =====
222 function updateCollectionStats(
223 string calldata _id,
224 uint256 initialBookCount,
225 uint256 dSafeBookCount
226 ) external onlyAdmin {
227 Collection storage c = collections[_id];
228 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
229
230 c.initialBookCount = initialBookCount;
231 c.dSafeBookCount = dSafeBookCount;
232 c.updatedAt = uint64(block.timestamp);
233 }
234
235 function setImportStatus(string calldata _id, ImportStatus status) external onlyAdmin {
236 Collection storage c = collections[_id];
237 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
238
239 c.importStatus = status;
240 c.updatedAt = uint64(block.timestamp);
241 }
242
243 function setPublished(string calldata _id, bool isPublished) external onlyAdmin {
244 Collection storage c = collections[_id];
245 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
246
247 c.published = isPublished;
248 c.updatedAt = uint64(block.timestamp);
249 }
250
251 function setCollectionPublicLibrary(string calldata _id, uint256 publicLibraryId) external onlyAdmin {
252 Collection storage c = collections[_id];
253 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
254 _validatePublicLibraryId(publicLibraryId);
255
256 c.publicLibraryId = publicLibraryId;
257 c.updatedAt = uint64(block.timestamp);
258 }
259}
260