diff --git a/api/docs/swagger.yaml b/api/docs/swagger.yaml index 8567c28cf..64741fbf2 100644 --- a/api/docs/swagger.yaml +++ b/api/docs/swagger.yaml @@ -901,27 +901,305 @@ paths: security: - api_key: [] - user_id: [] - /project: - get: - summary: Metadata about all projects - tags: - - "Project" - description: 'Returns the metadata about projects in the system, but not members of the projects.' - produces: - - "application/json" - operationId: "GetProjectList" - responses: - "401": - description: "Access denied." - "200": - description: "successful operation" - schema: - type: "array" - items: - $ref: "#/definitions/Project" - security: - - api_key: [] - - user_id: [] + /project: + get: + summary: Metadata about all projects + tags: + - "Project" + description: 'Returns the metadata about projects in the system, but not members of the projects.' + produces: + - "application/json" + operationId: "GetProjectList" + responses: + "401": + description: "Access denied." + "200": + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/Project" + security: + - api_key: [] + - user_id: [] + put: + summary: Create a new project + tags: + - "Project" + description: "Creates a new project record." + produces: + - "application/json" + operationId: "CreateProject" + parameters: + - in: body + name: "body" + required: true + schema: + $ref: "#/definitions/Project" + responses: + "401": + description: "Access denied." + "400": + description: "Invalid input." + "201": + description: "Project created." + security: + - api_key: [] + - user_id: [] + /project/{ProjectID}: + delete: + summary: Delete a project + tags: + - "Project" + description: "Deletes a project and removes all project membership links." + produces: + - "application/json" + operationId: "DeleteProject" + parameters: + - name: ProjectID + in: path + required: true + type: string + description: "ProjectID to delete" + allowEmptyValue: false + responses: + "401": + description: "Access denied." + "404": + description: "Project not found." + "200": + description: "successful operation" + security: + - api_key: [] + - user_id: [] + /project/{ProjectID}/devices: + get: + summary: Devices for a project + tags: + - "Project" + - "Device" + description: "Returns the list of devices associated with a project." + produces: + - "application/json" + operationId: "GetProjectDevices" + parameters: + - name: ProjectID + in: path + required: true + type: string + description: "ProjectID to retrieve devices for" + allowEmptyValue: false + responses: + "403": + description: "Access denied." + "404": + description: "Project not found." + "200": + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/ProjectDeviceView" + security: + - api_key: [] + - user_id: [] + /project/byname/{ProjectName}/devices: + get: + summary: Devices for a project by name + tags: + - "Project" + - "Device" + description: "Returns the list of devices associated with a project name." + produces: + - "application/json" + operationId: "GetProjectDevicesByName" + parameters: + - name: ProjectName + in: path + required: true + type: string + description: "Project name to retrieve devices for" + allowEmptyValue: false + responses: + "403": + description: "Access denied." + "404": + description: "Project not found." + "409": + description: "Multiple projects matched the supplied name." + "200": + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/ProjectDeviceView" + security: + - api_key: [] + - user_id: [] + /project/{ProjectID}/device: + post: + summary: Link a device to a project + tags: + - "Project" + - "Device" + description: "Associates a device with a project." + produces: + - "application/json" + operationId: "AddProjectDevice" + parameters: + - name: ProjectID + in: path + required: true + type: string + description: "ProjectID to update" + allowEmptyValue: false + - in: body + name: "body" + required: true + schema: + $ref: "#/definitions/ProjectDeviceLinkRequest" + responses: + "401": + description: "Access denied." + "404": + description: "Project or device not found." + "200": + description: "successful operation" + security: + - api_key: [] + - user_id: [] + /project/{ProjectID}/cabinet: + post: + summary: Link a cabinet to a project + tags: + - "Project" + - "Cabinet" + description: "Associates a cabinet with a project." + produces: + - "application/json" + operationId: "AddProjectCabinet" + parameters: + - name: ProjectID + in: path + required: true + type: string + description: "ProjectID to update" + allowEmptyValue: false + - in: body + name: "body" + required: true + schema: + $ref: "#/definitions/ProjectCabinetLinkRequest" + responses: + "401": + description: "Access denied." + "404": + description: "Project or cabinet not found." + "200": + description: "successful operation" + security: + - api_key: [] + - user_id: [] + /project/{ProjectID}/device/{DeviceID}: + delete: + summary: Unlink a device from a project + tags: + - "Project" + - "Device" + description: "Removes the device association from a project." + produces: + - "application/json" + operationId: "RemoveProjectDevice" + parameters: + - name: ProjectID + in: path + required: true + type: string + description: "ProjectID to update" + allowEmptyValue: false + - name: DeviceID + in: path + required: true + type: string + description: "DeviceID to remove" + allowEmptyValue: false + responses: + "401": + description: "Access denied." + "404": + description: "Project or device not found." + "200": + description: "successful operation" + security: + - api_key: [] + - user_id: [] + /project/{ProjectID}/cabinet/{CabinetID}: + delete: + summary: Unlink a cabinet from a project + tags: + - "Project" + - "Cabinet" + description: "Removes the cabinet association from a project." + produces: + - "application/json" + operationId: "RemoveProjectCabinet" + parameters: + - name: ProjectID + in: path + required: true + type: string + description: "ProjectID to update" + allowEmptyValue: false + - name: CabinetID + in: path + required: true + type: string + description: "CabinetID to remove" + allowEmptyValue: false + responses: + "401": + description: "Access denied." + "404": + description: "Project or cabinet not found." + "200": + description: "successful operation" + security: + - api_key: [] + - user_id: [] + /project/{ProjectID}/sendToStorage: + post: + summary: Send all project devices to storage + tags: + - "Project" + - "Device" + description: "Moves all devices in the project to the storage room." + produces: + - "application/json" + operationId: "SendProjectDevicesToStorage" + parameters: + - name: ProjectID + in: path + required: true + type: string + description: "ProjectID to update" + allowEmptyValue: false + - in: body + name: "body" + required: false + schema: + $ref: "#/definitions/SendToStorageRequest" + responses: + "401": + description: "Access denied." + "404": + description: "Project or storage room not found." + "200": + description: "successful operation" + schema: + $ref: "#/definitions/SendToStorageResponse" + security: + - api_key: [] + - user_id: [] /project/bycabinet/{CabinetID}: get: summary: Metadata about all projects associated with a specific cabinet @@ -1617,27 +1895,175 @@ definitions: Disabled: type: boolean format: "User has been disabled" - Project: - type: "object" - properties: - ProjectID: - type: "integer" - format: "keyValue" - ProjectName: - type: "string" - format: "Freeform text" - ProjectSponsor: - type: "string" - format: "Freeform text" - ProjectStartDate: - type: "string" - format: "Datestamp" - ProjectEndDate: - type: "string" - format: "Datestamp" - ProjectActualEndDate: - type: "string" - format: "Datestamp" + Project: + type: "object" + properties: + ProjectID: + type: "integer" + format: "keyValue" + ProjectName: + type: "string" + format: "Freeform text" + ProjectSponsor: + type: "string" + format: "Freeform text" + ProjectStartDate: + type: "string" + format: "Datestamp" + ProjectExpirationDate: + type: "string" + format: "Datestamp" + ProjectActualEndDate: + type: "string" + format: "Datestamp" + ProjectDeviceLinkRequest: + type: "object" + properties: + DeviceID: + type: "integer" + format: "keyValue" + ProjectCabinetLinkRequest: + type: "object" + properties: + CabinetID: + type: "integer" + format: "keyValue" + ProjectDeviceView: + type: "object" + properties: + DeviceID: + type: "integer" + format: "keyValue" + Label: + type: "string" + format: "string" + SerialNo: + type: "string" + format: "string" + AssetTag: + type: "string" + format: "string" + CabinetID: + type: "integer" + format: "keyValue" + CabinetName: + type: "string" + format: "string" + Position: + type: "integer" + format: "integer" + Height: + type: "integer" + format: "integer" + DeviceType: + type: "string" + format: "string" + Status: + type: "string" + format: "string" + PrimaryIP: + type: "string" + format: "string" + ParentDeviceID: + type: "integer" + format: "keyValue" + ParentDeviceLabel: + type: "string" + format: "string" + TemplateID: + type: "integer" + format: "keyValue" + TemplateModel: + type: "string" + format: "string" + ManufacturerID: + type: "integer" + format: "keyValue" + ManufacturerName: + type: "string" + format: "string" + DataCenterID: + type: "integer" + format: "keyValue" + DataCenterName: + type: "string" + format: "string" + CabRowID: + type: "integer" + format: "keyValue" + CabRowName: + type: "string" + format: "string" + ZoneID: + type: "integer" + format: "keyValue" + ZoneName: + type: "string" + format: "string" + DepartmentID: + type: "integer" + format: "keyValue" + DepartmentName: + type: "string" + format: "string" + Notes: + type: "string" + format: "string" + Tags: + type: "array" + items: + type: "string" + Rights: + type: "string" + format: "string" + SendToStorageRequest: + type: "object" + properties: + StorageRoomID: + type: "integer" + format: "keyValue" + ProjectDeviceMoveIssue: + type: "object" + properties: + DeviceID: + type: "integer" + format: "keyValue" + Reason: + type: "string" + format: "string" + SendToStorageSummary: + type: "object" + properties: + totalDevices: + type: "integer" + format: "integer" + moved: + type: "integer" + format: "integer" + skipped: + type: "integer" + format: "integer" + skippedDetails: + type: "array" + items: + $ref: "#/definitions/ProjectDeviceMoveIssue" + errors: + type: "array" + items: + $ref: "#/definitions/ProjectDeviceMoveIssue" + SendToStorageResponse: + type: "object" + properties: + error: + type: "boolean" + format: "boolean" + errorcode: + type: "integer" + format: "integer" + project: + $ref: "#/definitions/Project" + summary: + $ref: "#/definitions/SendToStorageSummary" PowerPort: type: "object" properties: diff --git a/api/v1/deleteRoutes.php b/api/v1/deleteRoutes.php index 19aa06c32..ddd971a13 100644 --- a/api/v1/deleteRoutes.php +++ b/api/v1/deleteRoutes.php @@ -178,6 +178,178 @@ function updatedevice($deviceid){ return $response->withJson($r, $r['errorcode']); }); +// +// URL: /api/v1/project/:projectid/device/:deviceid +// Method: DELETE +// Params: ProjectID, DeviceID +// Returns: true/false on update operation +// + +$app->delete( '/project/{projectid}/device/{deviceid}', function( Request $request, Response $response, $args ) use ( $person ) { + $projectid = intval( $args["projectid"] ); + $deviceid = intval( $args["deviceid"] ); + + if ( ! $person->WriteAccess ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + $project = Projects::getProject( $projectid ); + if ( ! $project ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Project not found"); + } else { + $dev = new Device(); + $dev->DeviceID = $deviceid; + if ( ! $dev->GetDevice() ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Device not found"); + } elseif ( $dev->Rights != "Write" ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + global $dbh; + $st = $dbh->prepare( "select 1 from fac_ProjectMembership where ProjectID=:ProjectID and MemberType='Device' and MemberID=:MemberID" ); + $st->execute( array( ":ProjectID"=>$projectid, ":MemberID"=>$deviceid ) ); + $exists = $st->fetchColumn(); + + if ( ! ProjectMembership::removeMember( $deviceid, "Device", $projectid ) ) { + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("Unable to unlink device from project."); + } else { + $r['error'] = false; + $r['errorcode'] = 200; + $r['message'] = $exists ? __("Device unlinked from project.") : __("Device link not found."); + } + } + } + } + + return $response->withJson( $r, $r['errorcode'] ); +}); + +// +// URL: /api/v1/project/:projectid/cabinet/:cabinetid +// Method: DELETE +// Params: ProjectID, CabinetID +// Returns: true/false on update operation +// + +$app->delete( '/project/{projectid}/cabinet/{cabinetid}', function( Request $request, Response $response, $args ) use ( $person ) { + $projectid = intval( $args["projectid"] ); + $cabinetid = intval( $args["cabinetid"] ); + + if ( ! $person->WriteAccess ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + $project = Projects::getProject( $projectid ); + if ( ! $project ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Project not found"); + } else { + $cab = new Cabinet(); + $cab->CabinetID = $cabinetid; + if ( ! $cab->GetCabinet() ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Cabinet not found"); + } elseif ( $cab->Rights != "Write" ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + global $dbh; + $st = $dbh->prepare( "select 1 from fac_ProjectMembership where ProjectID=:ProjectID and MemberType='Cabinet' and MemberID=:MemberID" ); + $st->execute( array( ":ProjectID"=>$projectid, ":MemberID"=>$cabinetid ) ); + $exists = $st->fetchColumn(); + + if ( ! ProjectMembership::removeMember( $cabinetid, "Cabinet", $projectid ) ) { + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("Unable to unlink cabinet from project."); + } else { + $r['error'] = false; + $r['errorcode'] = 200; + $r['message'] = $exists ? __("Cabinet unlinked from project.") : __("Cabinet link not found."); + } + } + } + } + + return $response->withJson( $r, $r['errorcode'] ); +}); + +// +// URL: /api/v1/project/:projectid +// Method: DELETE +// Params: ProjectID +// Returns: true/false on update operation +// + +$app->delete( '/project/{projectid}', function( Request $request, Response $response, $args ) use ( $person ) { + $projectid = intval( $args["projectid"] ); + + if ( ! $person->ContactAdmin ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + $project = Projects::getProject( $projectid ); + if ( ! $project ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Project not found"); + } else { + global $dbh; + try { + $st = $dbh->prepare( "select MemberType, count(*) as Total from fac_ProjectMembership where ProjectID=:ProjectID group by MemberType" ); + $st->execute( array( ":ProjectID"=>$projectid ) ); + $counts = array( "Device"=>0, "Cabinet"=>0 ); + while ( $row = $st->fetch( PDO::FETCH_ASSOC ) ) { + $counts[$row["MemberType"]] = intval( $row["Total"] ); + } + + $dbh->beginTransaction(); + + $st = $dbh->prepare( "delete from fac_ProjectMembership where ProjectID=:ProjectID" ); + $st->execute( array( ":ProjectID"=>$projectid ) ); + + $st = $dbh->prepare( "delete from fac_Projects where ProjectID=:ProjectID" ); + $st->execute( array( ":ProjectID"=>$projectid ) ); + + if ( $st->rowCount() < 1 ) { + throw new Exception("Delete failed"); + } + + $dbh->commit(); + + (class_exists('LogActions'))?LogActions::LogThis($project):''; + + $r['error'] = false; + $r['errorcode'] = 200; + $r['removedDeviceLinks'] = $counts["Device"]; + $r['removedCabinetLinks'] = $counts["Cabinet"]; + } catch ( Exception $e ) { + if ( $dbh->inTransaction() ) { + $dbh->rollBack(); + } + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("Project deletion failed."); + } + } + } + + return $response->withJson( $r, $r['errorcode'] ); +}); + // // URL: /api/v1/devicestatus/:statusid // Method: DELETE diff --git a/api/v1/getRoutes.php b/api/v1/getRoutes.php index 5d0b22043..05a05bcd8 100644 --- a/api/v1/getRoutes.php +++ b/api/v1/getRoutes.php @@ -698,6 +698,93 @@ }); +// Helper for retrieving device details for a project. +function getProjectDeviceList( $projectID ) { + global $dbh; + + $sql = "SELECT d.*, + c.CabinetID AS CabinetID, c.Location AS CabinetName, c.DataCenterID AS DataCenterID, dc.Name AS DataCenterName, + c.CabRowID AS CabRowID, cr.Name AS CabRowName, c.ZoneID AS ZoneID, z.Description AS ZoneName, + dt.Model AS TemplateModel, dt.ManufacturerID AS ManufacturerID, m.Name AS ManufacturerName, + dept.DeptID AS DepartmentID, dept.Name AS DepartmentName, + p.DeviceID AS ParentDeviceID, p.Label AS ParentDeviceLabel, + tags.TagList AS TagList + FROM fac_Device d + LEFT JOIN fac_DeviceTemplate dt ON d.TemplateID=dt.TemplateID + LEFT JOIN fac_Manufacturer m ON dt.ManufacturerID=m.ManufacturerID + LEFT JOIN fac_Cabinet c ON d.Cabinet=c.CabinetID + LEFT JOIN fac_DataCenter dc ON c.DataCenterID=dc.DataCenterID + LEFT JOIN fac_CabRow cr ON c.CabRowID=cr.CabRowID + LEFT JOIN fac_Zone z ON c.ZoneID=z.ZoneID + LEFT JOIN fac_Department dept ON d.Owner=dept.DeptID + LEFT JOIN fac_Device p ON d.ParentDevice=p.DeviceID + LEFT JOIN ( + SELECT dtg.DeviceID, GROUP_CONCAT(t.Name SEPARATOR '||') AS TagList + FROM fac_DeviceTags dtg + JOIN fac_Tags t ON dtg.TagID=t.TagID + GROUP BY dtg.DeviceID + ) tags ON d.DeviceID=tags.DeviceID + WHERE d.DeviceID IN ( + SELECT MemberID FROM fac_ProjectMembership WHERE ProjectID=:ProjectID AND MemberType='Device' + UNION + SELECT d2.DeviceID FROM fac_Device d2 WHERE d2.Cabinet IN ( + SELECT MemberID FROM fac_ProjectMembership WHERE ProjectID=:ProjectID AND MemberType='Cabinet' + ) + ) + ORDER BY d.Label ASC"; + + $st = $dbh->prepare( $sql ); + $st->execute( array( ":ProjectID"=>$projectID )); + + $devices = array(); + while ( $row = $st->fetch( PDO::FETCH_ASSOC ) ) { + $dev = Device::RowToObject( $row, true, false, false ); + + $device = array( + "DeviceID"=>$dev->DeviceID, + "Label"=>$dev->Label, + "SerialNo"=>$dev->SerialNo, + "AssetTag"=>$dev->AssetTag, + "CabinetID"=>$dev->Cabinet, + "Position"=>$dev->Position, + "Height"=>$dev->Height, + "DeviceType"=>$dev->DeviceType, + "Status"=>$dev->Status, + "PrimaryIP"=>$dev->PrimaryIP, + "ParentDeviceID"=>$dev->ParentDevice, + "Rights"=>$dev->Rights + ); + + if ( $dev->Rights != "None" ) { + $tags = array(); + if ( isset( $row["TagList"] ) && $row["TagList"] > "" ) { + $tags = array_filter( explode( "||", $row["TagList"] ) ); + } + + $device["TemplateID"] = $dev->TemplateID; + $device["TemplateModel"] = $row["TemplateModel"]; + $device["ManufacturerID"] = $row["ManufacturerID"]; + $device["ManufacturerName"] = $row["ManufacturerName"]; + $device["CabinetName"] = $row["CabinetName"]; + $device["DataCenterID"] = $row["DataCenterID"]; + $device["DataCenterName"] = $row["DataCenterName"]; + $device["CabRowID"] = $row["CabRowID"]; + $device["CabRowName"] = $row["CabRowName"]; + $device["ZoneID"] = $row["ZoneID"]; + $device["ZoneName"] = $row["ZoneName"]; + $device["DepartmentID"] = $row["DepartmentID"]; + $device["DepartmentName"] = $row["DepartmentName"]; + $device["ParentDeviceLabel"] = $row["ParentDeviceLabel"]; + $device["Notes"] = $dev->Notes; + $device["Tags"] = $tags; + } + + $devices[] = $device; + } + + return $devices; +} + // // URL: /api/v1/project // Method: GET @@ -745,6 +832,75 @@ return $response->withJson( $r, $r['errorcode'] ); }); +// +// URL: /api/v1/project/:projectid/devices +// Method: GET +// Params: ProjectID +// Returns: Devices assigned to the project +// + +$app->get( '/project/{projectid}/devices', function( Request $request, Response $response, $args ) use ( $person ) { + $projectid = intval($args["projectid"]); + + if ( ! $person->ReadAccess ) { + $r['error'] = true; + $r['errorcode'] = 403; + $r['message'] = __("Access Denied"); + } else { + $project = Projects::getProject( $projectid ); + if ( ! $project ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Project not found"); + } else { + $r['error'] = false; + $r['errorcode'] = 200; + $r['project'] = $project; + $r['device'] = getProjectDeviceList( $projectid ); + } + } + + return $response->withJson( $r, $r['errorcode'] ); +}); + +// +// URL: /api/v1/project/byname/:projectname/devices +// Method: GET +// Params: ProjectName +// Returns: Devices assigned to the project +// + +$app->get( '/project/byname/{projectname}/devices', function( Request $request, Response $response, $args ) use ( $person ) { + $projectname = $args["projectname"]; + + if ( ! $person->ReadAccess ) { + $r['error'] = true; + $r['errorcode'] = 403; + $r['message'] = __("Access Denied"); + } else { + $p = new Projects(); + $p->ProjectName = $projectname; + $projectList = $p->Search(); + if ( sizeof( $projectList ) == 0 ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Project not found"); + } elseif ( sizeof( $projectList ) > 1 ) { + $r['error'] = true; + $r['errorcode'] = 409; + $r['message'] = __("Multiple projects matched the supplied name."); + } else { + $project = $projectList[0]; + $r['error'] = false; + $r['errorcode'] = 200; + $r['project'] = $project; + $r['device'] = getProjectDeviceList( $project->ProjectID ); + } + } + + return $response->withJson( $r, $r['errorcode'] ); +}); + // // URL: /api/v1/powerport/:deviceid diff --git a/api/v1/postRoutes.php b/api/v1/postRoutes.php index 3fb75bce4..8ff52af06 100644 --- a/api/v1/postRoutes.php +++ b/api/v1/postRoutes.php @@ -366,6 +366,232 @@ return $response->withJson($r, $r['errorcode']); }); +// +// URL: /api/v1/project/:projectid/device +// Method: POST +// Params: DeviceID (required, body) +// Returns: true/false on update operation +// + +$app->post( '/project/{projectid}/device', function( Request $request, Response $response, $args ) use ( $person ) { + $projectid = intval( $args["projectid"] ); + + if ( ! $person->WriteAccess ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + $project = Projects::getProject( $projectid ); + if ( ! $project ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Project not found"); + } else { + $vars = $request->getQueryParams() ?: $request->getParsedBody(); + if ( ! isset( $vars["DeviceID"] ) ) { + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("DeviceID is required"); + } else { + $deviceid = intval( $vars["DeviceID"] ); + $dev = new Device(); + $dev->DeviceID = $deviceid; + if ( ! $dev->GetDevice() ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Device not found"); + } elseif ( $dev->Rights != "Write" ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + global $dbh; + $st = $dbh->prepare( "select 1 from fac_ProjectMembership where ProjectID=:ProjectID and MemberType='Device' and MemberID=:MemberID" ); + $st->execute( array( ":ProjectID"=>$projectid, ":MemberID"=>$deviceid ) ); + $exists = $st->fetchColumn(); + + if ( ! ProjectMembership::addMember( $projectid, $deviceid, "Device" ) ) { + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("Unable to link device to project."); + } else { + $r['error'] = false; + $r['errorcode'] = 200; + $r['message'] = $exists ? __("Device already linked to project.") : __("Device linked to project."); + $r['project'] = $project; + $r['device'] = $dev; + } + } + } + } + } + + return $response->withJson( $r, $r['errorcode'] ); +}); + +// +// URL: /api/v1/project/:projectid/cabinet +// Method: POST +// Params: CabinetID (required, body) +// Returns: true/false on update operation +// + +$app->post( '/project/{projectid}/cabinet', function( Request $request, Response $response, $args ) use ( $person ) { + $projectid = intval( $args["projectid"] ); + + if ( ! $person->WriteAccess ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + $project = Projects::getProject( $projectid ); + if ( ! $project ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Project not found"); + } else { + $vars = $request->getQueryParams() ?: $request->getParsedBody(); + if ( ! isset( $vars["CabinetID"] ) ) { + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("CabinetID is required"); + } else { + $cabinetid = intval( $vars["CabinetID"] ); + $cab = new Cabinet(); + $cab->CabinetID = $cabinetid; + if ( ! $cab->GetCabinet() ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Cabinet not found"); + } elseif ( $cab->Rights != "Write" ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + global $dbh; + $st = $dbh->prepare( "select 1 from fac_ProjectMembership where ProjectID=:ProjectID and MemberType='Cabinet' and MemberID=:MemberID" ); + $st->execute( array( ":ProjectID"=>$projectid, ":MemberID"=>$cabinetid ) ); + $exists = $st->fetchColumn(); + + if ( ! ProjectMembership::addMember( $projectid, $cabinetid, "Cabinet" ) ) { + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("Unable to link cabinet to project."); + } else { + $r['error'] = false; + $r['errorcode'] = 200; + $r['message'] = $exists ? __("Cabinet already linked to project.") : __("Cabinet linked to project."); + $r['project'] = $project; + $r['cabinet'] = $cab; + } + } + } + } + } + + return $response->withJson( $r, $r['errorcode'] ); +}); + +// +// URL: /api/v1/project/:projectid/sendToStorage +// Method: POST +// Params: StorageRoomID (optional, body) +// Returns: Summary of processed devices +// + +$app->post( '/project/{projectid}/sendToStorage', function( Request $request, Response $response, $args ) use ( $person ) { + $projectid = intval( $args["projectid"] ); + + if ( ! $person->WriteAccess ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + $project = Projects::getProject( $projectid ); + if ( ! $project ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Project not found"); + } else { + $vars = $request->getQueryParams() ?: $request->getParsedBody(); + $storageRoomID = null; + + if ( isset( $vars["StorageRoomID"] ) ) { + $storageRoomID = intval( $vars["StorageRoomID"] ); + if ( $storageRoomID < 0 ) { + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("Invalid StorageRoomID"); + return $response->withJson( $r, $r['errorcode'] ); + } + if ( $storageRoomID > 0 ) { + $dc = new DataCenter(); + $dc->DataCenterID = $storageRoomID; + if ( ! $dc->GetDataCenterbyID() ) { + $r['error'] = true; + $r['errorcode'] = 404; + $r['message'] = __("Storage room not found."); + return $response->withJson( $r, $r['errorcode'] ); + } + } + } + + $deviceList = ProjectMembership::getProjectMembership( $projectid, true, true ); + $summary = array( + "totalDevices"=>sizeof( $deviceList ), + "moved"=>0, + "skipped"=>0, + "skippedDetails"=>array(), + "errors"=>array() + ); + + foreach ( $deviceList as $deviceID => $deviceRow ) { + $dev = new Device(); + $dev->DeviceID = $deviceID; + + if ( ! $dev->GetDevice() ) { + $summary["errors"][] = array( + "DeviceID"=>$deviceID, + "Reason"=>"Device not found" + ); + continue; + } + + if ( $dev->Rights != "Write" ) { + $summary["skipped"]++; + $summary["skippedDetails"][] = array( + "DeviceID"=>$deviceID, + "Reason"=>"Access denied" + ); + continue; + } + + $dev->MoveToStorage(); + + if ( $storageRoomID !== null ) { + $dev->Position = $storageRoomID; + if ( ! $dev->UpdateDevice() ) { + $summary["errors"][] = array( + "DeviceID"=>$deviceID, + "Reason"=>"Unable to update storage room" + ); + continue; + } + } + + $summary["moved"]++; + } + + $r['error'] = false; + $r['errorcode'] = 200; + $r['project'] = $project; + $r['summary'] = $summary; + } + } + + return $response->withJson( $r, $r['errorcode'] ); +}); + // // URL: /api/v1/devicetemplate/:templateid // Method: POST diff --git a/api/v1/putRoutes.php b/api/v1/putRoutes.php index 38f9fbfcb..84f2d3aa1 100644 --- a/api/v1/putRoutes.php +++ b/api/v1/putRoutes.php @@ -75,6 +75,77 @@ return $response->withJson($r, $r['errorcode']); }); +// +// URL: /api/v1/project +// Method: PUT +// Params: ProjectName (required) +// Returns: record as created +// + +$app->put( '/project', function( Request $request, Response $response ) use ( $person ) { + if ( ! $person->WriteAccess ) { + $r['error'] = true; + $r['errorcode'] = 401; + $r['message'] = __("Access Denied"); + } else { + $project = new Projects(); + $vars = $request->getQueryParams() ?: $request->getParsedBody(); + + foreach ( $vars as $prop=>$val ) { + if ( property_exists( $project, $prop ) ) { + $project->$prop = $val; + } + } + + $project->ProjectName = trim( $project->ProjectName ); + if ( $project->ProjectName == "" ) { + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("ProjectName is required"); + } else { + if ( $project->ProjectStartDate > "" ) { + $project->ProjectStartDate = date( "Y-m-d", strtotime( $project->ProjectStartDate ) ); + } else { + $project->ProjectStartDate = null; + } + if ( $project->ProjectExpirationDate > "" ) { + $project->ProjectExpirationDate = date( "Y-m-d", strtotime( $project->ProjectExpirationDate ) ); + } else { + $project->ProjectExpirationDate = null; + } + if ( $project->ProjectActualEndDate > "" ) { + $project->ProjectActualEndDate = date( "Y-m-d", strtotime( $project->ProjectActualEndDate ) ); + } else { + $project->ProjectActualEndDate = null; + } + + $search = new Projects(); + $search->ProjectName = $project->ProjectName; + $existing = $search->Search(); + + if ( sizeof( $existing ) > 0 ) { + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("Project name already exists."); + } else { + $project->createProject(); + if ( $project->ProjectID == false ) { + $r['error'] = true; + $r['errorcode'] = 400; + $r['message'] = __("Unable to create Project resource with the given parameters."); + } else { + $r['error'] = false; + $r['errorcode'] = 201; + $r['message'] = __("Project resource created successfully."); + $r['project'] = $project; + } + } + } + } + + return $response->withJson( $r, $r['errorcode'] ); +}); + // // URL: /api/v1/people/:userid // Method: PUT