// @ts-check
/**
* Share controllers (contract envelope).
* @import {ExpressRequestAuthorized, ExpressResponse} from '../../types.js'
*/
import { sendOk, sendErrorFrom } from '../../utils/apiEnvelope.js';
import * as service from './service.js';
/**
* @swagger
* /api/project/project/{projectUid}/shares:
* put:
* summary: Add a share to a project
* description: |
* Creates a repositoryShare or directoryShare belonging to exactly one
* project. Requires `admin` on the project. Shares carry no own ACL.
* tags:
* - Project Shares
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: projectUid
* required: true
* schema:
* type: string
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/ShareCreateBody'
* responses:
* 200:
* description: Share created
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/SuccessResponse'
* 422:
* description: Invalid share type or metadata (e.g. ACL/capabilities present)
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/ErrorResponse'
* get:
* summary: List shares of a project
* description: Requires at least `visible` on the project (derived right).
* tags:
* - Project Shares
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: projectUid
* required: true
* schema:
* type: string
* responses:
* 200:
* description: List of shares
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/SuccessResponse'
*/
/**
* @swagger
* /api/project/project/shares/search:
* get:
* summary: Search org repository shares visible to the user
* description: |
* Returns repositoryShare/directoryShare objects of the organization that
* are linked to at least one project visible to the current user
* (admins see all org shares). Used by the "add existing repository" flow.
* The response is a raw array (SearchSelect-compatible).
* tags:
* - Project Shares
* security:
* - bearerAuth: []
* parameters:
* - in: query
* name: search
* required: false
* schema:
* type: string
* description: Terms matching title, display, repositoryKey or gitUrl
* - in: query
* name: excludeProject
* required: false
* schema:
* type: string
* description: Share UID of a project whose already-linked shares are skipped
* responses:
* 200:
* description: Array of matching shares
* content:
* application/json:
* schema:
* type: array
* items:
* $ref: './projectShare.swagger.yaml#/components/schemas/ShareSearchItem'
* 401:
* description: Missing or invalid authentication
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/ErrorResponse'
*/
/**
* GET /project/project/shares/search
* @param {ExpressRequestAuthorized} req
* @param {ExpressResponse} res
*/
export const searchShares = async (req, res) => {
try {
const result = await service.searchShares(req, req.query.search, req.query.excludeProject);
// Raw array — die SearchSelect-Komponente erwartet ein Array als Antwort
res.json(result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* PUT /project/project/:projectUid/shares
* @param {ExpressRequestAuthorized} req
* @param {ExpressResponse} res
*/
export const postShare = async (req, res) => {
try {
const result = await service.addShare(req, req.params.projectUid);
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* GET /project/project/:projectUid/shares
* @param {ExpressRequestAuthorized} req
* @param {ExpressResponse} res
*/
export const listShares = async (req, res) => {
try {
const result = await service.listShares(req, req.params.projectUid);
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* @swagger
* /api/project/project/{projectUid}/shares/{shareUid}:
* post:
* summary: Update share metadata
* description: Requires `admin` on the parent project. No ACL/capabilities allowed.
* tags:
* - Project Shares
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: projectUid
* required: true
* schema:
* type: string
* - in: path
* name: shareUid
* required: true
* schema:
* type: string
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/ShareUpdateBody'
* responses:
* 200:
* description: Share updated
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/SuccessResponse'
* 404:
* description: Share not found for this project
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/ErrorResponse'
* delete:
* summary: Delete a share
* description: |
* Removes the projectShare link and the share object in one transaction.
* Requires `admin` on the parent project.
* tags:
* - Project Shares
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: projectUid
* required: true
* schema:
* type: string
* - in: path
* name: shareUid
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Share deleted
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/SuccessResponse'
* 404:
* description: Share not found for this project
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/ErrorResponse'
*/
/**
* POST /project/project/:projectUid/shares/:shareUid
* @param {ExpressRequestAuthorized} req
* @param {ExpressResponse} res
*/
export const updateShare = async (req, res) => {
try {
const result = await service.updateShare(req, req.params.projectUid, req.params.shareUid);
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* DELETE /project/project/:projectUid/shares/:shareUid
* @param {ExpressRequestAuthorized} req
* @param {ExpressResponse} res
*/
export const deleteShare = async (req, res) => {
try {
const result = await service.deleteShare(req, req.params.projectUid, req.params.shareUid);
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* @swagger
* /api/project/project/{projectUid}/shares/{shareUid}/link:
* post:
* summary: Link an existing share to a project
* description: |
* Links an org-owned share to the project. Requires `admin` on the
* project. `linkType` 'memberA' grants write/admin (Master-Projekt),
* 'member' grants read only. Fires /add/project/{read|write}/{projectUid}.
* tags:
* - Project Shares
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: projectUid
* required: true
* schema:
* type: string
* - in: path
* name: shareUid
* required: true
* schema:
* type: string
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* linkType:
* type: string
* enum: [memberA, member]
* responses:
* 200:
* description: Share linked
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/SuccessResponse'
* 404:
* description: Share not found in this organization
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/ErrorResponse'
* delete:
* summary: Remove the link between a share and a project
* description: |
* Removes the memberA/member link. Requires `admin` on the project.
* Fires /remove/project/{read|write}/{projectUid}. The share object
* itself is kept.
* tags:
* - Project Shares
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: projectUid
* required: true
* schema:
* type: string
* - in: path
* name: shareUid
* required: true
* schema:
* type: string
* responses:
* 200:
* description: Share unlinked
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/SuccessResponse'
* 404:
* description: Share not linked to this project
* content:
* application/json:
* schema:
* $ref: './projectShare.swagger.yaml#/components/schemas/ErrorResponse'
*/
/**
* POST /project/project/:projectUid/shares/:shareUid/link
* @param {ExpressRequestAuthorized} req
* @param {ExpressResponse} res
*/
export const linkShare = async (req, res) => {
try {
const result = await service.linkShare(req, req.params.projectUid, req.params.shareUid);
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};
/**
* DELETE /project/project/:projectUid/shares/:shareUid/link
* @param {ExpressRequestAuthorized} req
* @param {ExpressResponse} res
*/
export const unlinkShare = async (req, res) => {
try {
const result = await service.unlinkShare(req, req.params.projectUid, req.params.shareUid);
sendOk(res, result.result);
} catch (e) {
sendErrorFrom(res, e);
}
};