Skip to content

Commit 807803d

Browse files
committed
feat(project): grant SFTP users access to all directories
The mittwald API requires at least one directory, so there was no way to express what mStudio offers as a checkbox. Create SFTP User now carries that switch and sends the project root as the single directory, matching what mStudio stores for the same option. Closes #58
1 parent 2dff507 commit 807803d

3 files changed

Lines changed: 55 additions & 6 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ This node provides integration with the [mittwald API v2](https://developer.mitt
112112

113113
- **Create a project on a server**: Create a new project on a server
114114
- **Create an SSH user**: Create an SSH user for a project (parameters: Project, Name, Password, optional Expires At)
115-
- **Create an SFTP user**: Create an SFTP user for a project (parameters: Project, Name, Password, Access Level, Directories, optional Expires At)
115+
- **Create an SFTP user**: Create an SFTP user for a project (parameters: Project, Name, Password, Access Level, Access to All Directories, Directories, optional Expires At). Turning on _Access to All Directories_ grants the user the whole project, exactly as the equivalent option in mStudio does; leave it off to name directories individually.
116116
- **Delete an SSH user**: Delete an SSH user from a project (parameter: SSH User ID)
117117
- **Delete an SFTP user**: Delete an SFTP user from a project (parameter: SFTP User ID)
118118
- **Get an SSH user**: Get details of a specific SSH user (parameter: SSH User ID)

nodes/Mittwald/resources/implementations/Project/operations/createSftpUser.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,25 @@ export default projectResource
4747
},
4848
],
4949
},
50+
allDirectories: {
51+
displayName: 'Access to All Directories',
52+
type: 'boolean',
53+
required: false,
54+
default: false,
55+
description:
56+
'Whether the user may access every directory of the project. Turn this off to name the directories individually.',
57+
},
5058
directories: {
5159
displayName: 'Directories',
5260
type: 'string',
5361
required: true,
5462
default: '',
5563
description: 'One or more directories, separated by commas or new lines',
64+
displayOptions: {
65+
show: {
66+
allDirectories: [false],
67+
},
68+
},
5669
},
5770
expiresAt: {
5871
displayName: 'Expires At',
@@ -63,11 +76,15 @@ export default projectResource
6376
},
6477
})
6578
.withExecuteFn(async ({ properties, apiClient }) => {
66-
const { project, description, password, accessLevel, directories, expiresAt } = properties;
67-
const parsedDirectories = directories
68-
.split(/\n|,/)
69-
.map((directory) => directory.trim())
70-
.filter((directory) => directory.length > 0);
79+
const { project, description, password, accessLevel, allDirectories, directories, expiresAt } =
80+
properties;
81+
// The project root is what mStudio stores for "access to all directories".
82+
const parsedDirectories = allDirectories
83+
? ['/']
84+
: directories
85+
.split(/\n|,/)
86+
.map((directory) => directory.trim())
87+
.filter((directory) => directory.length > 0);
7188

7289
if (parsedDirectories.length === 0) {
7390
throw new Error('At least one directory is required');

test/integration/project.sftp-user.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ integrationDescribe('Project / SFTP User (integration)', () => {
5050
directories: '/html',
5151
},
5252
})
53+
.step({
54+
name: 'Create SFTP User With Full Access',
55+
resource: 'Project',
56+
operation: 'Create SFTP User',
57+
parameters: {
58+
project: fromStep('Create Project'),
59+
description: `${userDescription}-all`,
60+
password,
61+
accessLevel: 'read',
62+
allDirectories: true,
63+
},
64+
})
5365
.step({
5466
name: 'List SFTP Users',
5567
resource: 'Project',
@@ -66,11 +78,31 @@ integrationDescribe('Project / SFTP User (integration)', () => {
6678
sftpUserId: fromStep('Create SFTP User'),
6779
},
6880
})
81+
.step({
82+
name: 'Delete SFTP User With Full Access',
83+
resource: 'Project',
84+
operation: 'Delete SFTP User',
85+
parameters: {
86+
sftpUserId: fromStep('Create SFTP User With Full Access'),
87+
},
88+
})
6989
.run();
7090

7191
const projectId = result.step('Create Project').requireString('id');
7292
const sftpUserId = result.step('Create SFTP User').requireString('id');
93+
const fullAccessUserId = result.step('Create SFTP User With Full Access').requireString('id');
7394
expect(result.step('Create SFTP User').requireString('projectId')).toBe(projectId);
95+
7496
expect(result.step('List SFTP Users').stringValues('id')).toContain(sftpUserId);
97+
expect(result.step('List SFTP Users').stringValues('id')).toContain(fullAccessUserId);
98+
99+
// "Access to All Directories" has to reach the API as the project root. Read back from the
100+
// list instead of Get SFTP User: right after creation the API still answers a lookup by id
101+
// with "access denied; verdict: abstain".
102+
const fullAccessUser = result
103+
.step('List SFTP Users')
104+
.items()
105+
.find((item) => item.json.id === fullAccessUserId);
106+
expect(fullAccessUser?.json.directories).toEqual(['/']);
75107
});
76108
});

0 commit comments

Comments
 (0)