📄 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 function formatExists(string calldata format) external view returns (bool);
24}
25
26contract LibraryRegistryStorage {
27
28 enum LibraryType {
29 Online,
30 PhysicalWithDigitalCopies
31 }
32
33 enum ImportStatus {
34 Pending,
35 InProgress,
36 Completed,
37 Failed
38 }
39
40 struct Collection {
41 string id;
42 string slug;
43 string manifestUrl;
44 string importerUsername;
45 address owner;
46 bool verified;
47 uint256 fileCount;
48 LibraryType libraryType;
49 uint256 publicLibraryId; // 0 = not linked to a PublicLibraryStorage entry
50 string language;
51 bool isPublic;
52 uint64 createdAt;
53 uint64 updatedAt;
54 uint256 initialBookCount;
55 uint256 dSafeBookCount;
56 ImportStatus importStatus;
57 bool published;
58 string preferredFormat;
59 }
60
61 struct CollectionInput {
62 string id;
63 string slug;
64 string manifestUrl;
65 string importerUsername;
66 address owner;
67 uint256 fileCount;
68 LibraryType libraryType;
69 uint256 publicLibraryId; // 0 = not linked to a PublicLibraryStorage entry
70 string language;
71 bool isPublic;
72 uint256 initialBookCount;
73 uint256 dSafeBookCount;
74 string preferredFormat;
75 }
76
77 // State Variables
78 address public admin; // single admin or multi-sig if you choose
79 mapping(address => bool) public _isAuthorized; // reserved for future write access (unused for now)
80 IPublicLibraryStorage public publicLibraryStorage;
81
82 // Collection Storage
83 mapping(string => Collection) private collections;
84
85 string[] private unverifiedCollectionIds;
86 string[] private verifiedCollectionIds;
87
88 event AuthorizedAdded(address indexed caller);
89 event AuthorizedRemoved(address indexed caller);
90
91 // Modifiers
92 modifier onlyAdmin() {
93 require(msg.sender == admin, "not admin");
94 _;
95 }
96
97 modifier onlyAuthorized() {
98 require(_isAuthorized[msg.sender], "not authorized");
99 _;
100 }
101
102 constructor() {
103 admin = msg.sender;
104 }
105
106 // ===== Admin / authorization (reserved for future write access) =====
107 function isAuthorized(address caller) public view returns (bool) {
108 require(caller != address(0), "zero addr");
109 return _isAuthorized[caller];
110 }
111
112 function addAuthorized(address caller) public onlyAdmin {
113 require(caller != address(0), "zero addr");
114 _isAuthorized[caller] = true;
115 emit AuthorizedAdded(caller);
116 }
117
118 function removeAuthorized(address caller) public onlyAdmin {
119 _isAuthorized[caller] = false;
120 emit AuthorizedRemoved(caller);
121 }
122
123 function setPublicLibraryStorage(address storageAddr) external onlyAdmin {
124 if (storageAddr == address(0)) revert ErrorLibrary.EmptyAddress();
125 publicLibraryStorage = IPublicLibraryStorage(storageAddr);
126 }
127
128 // 0 means "not linked" and is always allowed; a non-zero id must exist in PublicLibraryStorage.
129 function _validatePublicLibraryId(uint256 publicLibraryId) internal view {
130 if (publicLibraryId == 0) return;
131 if (address(publicLibraryStorage) == address(0) || !publicLibraryStorage.libraryExists(publicLibraryId)) {
132 revert ErrorLibrary.InvalidPublicLibraryId();
133 }
134 }
135
136 function _validateFormat(string calldata format) internal view {
137 if (address(publicLibraryStorage) == address(0) || !publicLibraryStorage.formatExists(format)) {
138 revert ErrorLibrary.InvalidFormat();
139 }
140 }
141
142 // Public Submission — admin-only for now (Called by Orchestrator on Arweave Upload Success)
143 function addUnverifiedCollection(CollectionInput calldata input) external onlyAdmin {
144 if (bytes(collections[input.id].id).length != 0) {
145 revert ErrorLibrary.ErrAlreadyRegistered();
146 }
147 _validatePublicLibraryId(input.publicLibraryId);
148 _validateFormat(input.preferredFormat);
149
150 uint64 nowTs = uint64(block.timestamp);
151
152 collections[input.id] = Collection({
153 id: input.id,
154 slug: input.slug,
155 manifestUrl: input.manifestUrl,
156 importerUsername: input.importerUsername,
157 owner: input.owner,
158 verified: false,
159 fileCount: input.fileCount,
160 libraryType: input.libraryType,
161 publicLibraryId: input.publicLibraryId,
162 language: input.language,
163 isPublic: input.isPublic,
164 createdAt: nowTs,
165 updatedAt: nowTs,
166 initialBookCount: input.initialBookCount,
167 dSafeBookCount: input.dSafeBookCount,
168 importStatus: ImportStatus.Pending,
169 published: false,
170 preferredFormat: input.preferredFormat
171 });
172
173 unverifiedCollectionIds.push(input.id);
174 }
175
176 // Admin-only Read Operations (Access Control Restricted)
177 function getUnverifiedCollectionIds() external view onlyAdmin returns (string[] memory) {
178 return unverifiedCollectionIds;
179 }
180
181 // Public Read Operations
182 function getVerifiedCollectionIds() external view returns (string[] memory) {
183 return verifiedCollectionIds;
184 }
185
186 function getCollection(string calldata _id) external view returns (Collection memory) {
187 Collection memory c = collections[_id];
188 // Enforce that unverified collections are only viewable by the admin or the owner
189 if (!c.verified && msg.sender != admin && c.owner != msg.sender) {
190 revert ErrorLibrary.Forbidden(msg.sender);
191 }
192 return c;
193 }
194
195 // Manual Verification Workflow (admin-only for now)
196 function verifyCollection(string calldata _id) external onlyAdmin {
197 Collection storage c = collections[_id];
198 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
199 if (c.verified) revert ErrorLibrary.ErrAlreadyRegistered();
200
201 c.verified = true;
202 c.updatedAt = uint64(block.timestamp);
203 verifiedCollectionIds.push(_id);
204
205 // Remove from unverified list
206 for (uint256 i = 0; i < unverifiedCollectionIds.length; i++) {
207 if (keccak256(bytes(unverifiedCollectionIds[i])) == keccak256(bytes(_id))) {
208 unverifiedCollectionIds[i] = unverifiedCollectionIds[unverifiedCollectionIds.length - 1];
209 unverifiedCollectionIds.pop();
210 break;
211 }
212 }
213 }
214
215 function rejectCollection(string calldata _id) external onlyAdmin {
216 Collection memory c = collections[_id];
217 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
218 if (c.verified) revert ErrorLibrary.ErrAlreadyRegistered();
219
220 delete collections[_id];
221
222 // Remove from unverified list
223 for (uint256 i = 0; i < unverifiedCollectionIds.length; i++) {
224 if (keccak256(bytes(unverifiedCollectionIds[i])) == keccak256(bytes(_id))) {
225 unverifiedCollectionIds[i] = unverifiedCollectionIds[unverifiedCollectionIds.length - 1];
226 unverifiedCollectionIds.pop();
227 break;
228 }
229 }
230 }
231
232 // ===== Lifecycle updates (admin-only for now) =====
233 function updateCollectionStats(
234 string calldata _id,
235 uint256 initialBookCount,
236 uint256 dSafeBookCount
237 ) external onlyAdmin {
238 Collection storage c = collections[_id];
239 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
240
241 c.initialBookCount = initialBookCount;
242 c.dSafeBookCount = dSafeBookCount;
243 c.updatedAt = uint64(block.timestamp);
244 }
245
246 function setImportStatus(string calldata _id, ImportStatus status) external onlyAdmin {
247 Collection storage c = collections[_id];
248 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
249
250 c.importStatus = status;
251 c.updatedAt = uint64(block.timestamp);
252 }
253
254 function setPublished(string calldata _id, bool isPublished) external onlyAdmin {
255 Collection storage c = collections[_id];
256 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
257
258 c.published = isPublished;
259 c.updatedAt = uint64(block.timestamp);
260 }
261
262 function setCollectionPublicLibrary(string calldata _id, uint256 publicLibraryId) external onlyAdmin {
263 Collection storage c = collections[_id];
264 if (bytes(c.id).length == 0) revert ErrorLibrary.InvalidProjectId();
265 _validatePublicLibraryId(publicLibraryId);
266
267 c.publicLibraryId = publicLibraryId;
268 c.updatedAt = uint64(block.timestamp);
269 }
270}
271