• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Lumieducation / H5P-Nodejs-library / 5761e0b3-9bed-478e-9d39-fb32070e15c2

pending completion
5761e0b3-9bed-478e-9d39-fb32070e15c2

push

circleci

renovate[bot]
chore(deps): lock file maintenance

4682 of 8584 branches covered (54.54%)

Branch coverage included in aggregate %.

8640 of 11846 relevant lines covered (72.94%)

2234.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

16.67
/packages/h5p-server/src/LibraryAdministration.ts
1
import LibraryManager from './LibraryManager';
2
import ContentManager from './ContentManager';
3
import H5pError from './helpers/H5pError';
6✔
4
import LibraryName from './LibraryName';
6✔
5
import {
6
    ILibraryName,
7
    ILibraryAdministrationOverviewItem,
8
    IInstalledLibrary
9
} from './types';
10
import Logger from './helpers/Logger';
6✔
11

12
const log = new Logger('LibraryAdministration');
6✔
13

14
/**
15
 * This class has methods that perform library administration, i.e, deleted
16
 * libraries. All parameters undergo validation and proper exceptions are thrown
17
 * when something went wrong.
18
 */
19
export default class LibraryAdministration {
6✔
20
    constructor(
21
        protected libraryManager: LibraryManager,
×
22
        protected contentManager: ContentManager
×
23
    ) {}
24

25
    /**
26
     * Deletes a library.
27
     *
28
     * Throws H5pError with HTTP status code 423 if the library cannot be
29
     * deleted because it is still in use.
30
     * @param ubername the ubername of the library to delete
31
     */
32
    public async deleteLibrary(ubername: string): Promise<void> {
6✔
33
        const libraryName = await this.checkLibrary(ubername);
×
34

35
        // Check if library can be safely deleted
36
        const usage = await this.contentManager.contentStorage.getUsage(
×
37
            libraryName
38
        );
39
        const dependentsCount =
×
40
            await this.libraryManager.libraryStorage.getDependentsCount(
×
41
                libraryName
42
            );
43
        if (usage.asDependency + usage.asMainLibrary + dependentsCount > 0) {
×
44
            throw new H5pError('library-used', { library: ubername }, 423);
×
45
        }
46
        await this.libraryManager.libraryStorage.deleteLibrary(libraryName);
×
47
    }
48

49
    /**
50
     * Lists all installed libraries. This operation can be relatively costly
51
     * as it has to go through the whole library metadata and calculate
52
     * usage of libraries across all content objects on the system.
53
     */
54
    public async getLibraries(): Promise<ILibraryAdministrationOverviewItem[]> {
6✔
55
        log.debug('Getting all libraries');
×
56
        const libraryNames =
×
57
            await this.libraryManager.libraryStorage.getInstalledLibraryNames();
×
58
        const libraryMetadata = (
×
59
            await Promise.all(
×
60
                libraryNames.map((lib) => this.libraryManager.getLibrary(lib))
×
61
            )
62
        ).sort((a, b) => a.compare(b));
×
63

64
        log.debug('Getting all dependents count');
×
65
        const dependents =
×
66
            await this.libraryManager.libraryStorage.getAllDependentsCount();
×
67

68
        return Promise.all(
×
69
            libraryMetadata.map(async (metadata) => {
×
70
                log.debug(
×
71
                    `Getting usage data of ${LibraryName.toUberName(metadata)}`
72
                );
73
                const usage = await this.contentManager.contentStorage.getUsage(
×
74
                    metadata
75
                );
76
                const dependentsCount =
×
77
                    dependents[LibraryName.toUberName(metadata)] ?? 0;
×
78
                return {
×
79
                    title: metadata.title,
80
                    machineName: metadata.machineName,
81
                    majorVersion: metadata.majorVersion,
82
                    minorVersion: metadata.minorVersion,
83
                    patchVersion: metadata.patchVersion,
84
                    isAddon: metadata.addTo !== undefined,
85
                    restricted: metadata.restricted,
86
                    // We coerce the inconsistent H5P type boolean | 0 | 1 into
87
                    // boolean.
88
                    // eslint-disable-next-line eqeqeq
89
                    runnable: metadata.runnable == true,
90
                    instancesCount: usage.asMainLibrary,
91
                    instancesAsDependencyCount: usage.asDependency,
92
                    dependentsCount,
93
                    canBeDeleted:
94
                        usage.asDependency +
95
                            usage.asMainLibrary +
96
                            dependentsCount ===
97
                        0,
98
                    // libraries can be updated if there is an installed library
99
                    // with the same machine name but a greater version
100
                    canBeUpdated: libraryNames.some(
101
                        (ln) =>
102
                            ln.machineName === metadata.machineName &&
×
103
                            metadata.compareVersions(ln) < 0
104
                    )
105
                };
106
            })
107
        );
108
    }
109

110
    /**
111
     * Returns detailed information about the library and its use.
112
     * @param ubername
113
     */
114
    public async getLibrary(ubername: string): Promise<
6✔
115
        IInstalledLibrary & {
116
            /**
117
             * How many libraries depend on this library.
118
             */
119
            dependentsCount: number;
120
            /**
121
             * How often this library is used in content objects, but only as a
122
             * dependency.
123
             */
124
            instancesAsDependencyCount: number;
125
            /**
126
             * How often this library is used in content object as main library.
127
             */
128
            instancesCount: number;
129
            /**
130
             * Whether the library is an addon.
131
             */
132
            isAddon: boolean;
133
        }
134
    > {
135
        const libraryName = await this.checkLibrary(ubername);
×
136
        const [metadata, usage, dependentsCount] = await Promise.all([
×
137
            this.libraryManager.getLibrary(libraryName),
138
            this.contentManager.contentStorage.getUsage(libraryName),
139
            this.libraryManager.libraryStorage.getDependentsCount(libraryName)
140
        ]);
141
        return {
×
142
            ...metadata,
143
            dependentsCount,
144
            instancesCount: usage.asMainLibrary,
145
            instancesAsDependencyCount: usage.asDependency,
146
            isAddon: metadata.addTo !== undefined
147
        };
148
    }
149

150
    /**
151
     * Changes the restricted status of a library
152
     * @param ubername the library's ubername you want to change
153
     * @param restricted the new value
154
     */
155
    public async restrictLibrary(
6✔
156
        ubername: string,
157
        restricted: boolean
158
    ): Promise<void> {
159
        const libraryName = await this.checkLibrary(ubername);
×
160
        if (restricted === undefined || typeof restricted !== 'boolean') {
×
161
            throw new H5pError('invalid-patch-request', undefined, 400);
×
162
        }
163

164
        await this.libraryManager.libraryStorage.updateAdditionalMetadata(
×
165
            libraryName,
166
            { restricted }
167
        );
168
    }
169

170
    /**
171
     * Checks if the ubername is valid and if the library is installed.
172
     * Throws H5pErrors if the name is invalid (400) or the library is not
173
     * installed (404).
174
     * @param ubername the ubername to check
175
     * @returns the parsed library name
176
     */
177
    private async checkLibrary(ubername: string): Promise<ILibraryName> {
6✔
178
        // Check for correct ubername
179
        const libraryName = LibraryName.fromUberName(ubername);
×
180
        if (libraryName === undefined) {
×
181
            throw new H5pError(
×
182
                'invalid-ubername-pattern',
183
                { name: ubername },
184
                400
185
            );
186
        }
187

188
        // Check if library is installed
189
        if (
×
190
            !(await this.libraryManager.libraryStorage.isInstalled(libraryName))
×
191
        ) {
192
            throw new H5pError('library-missing', { library: ubername }, 404);
×
193
        }
194
        return libraryName;
×
195
    }
196
}
6✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc