You are viewing an old version of this page. View the current version.

Compare with Current Restore this Version View Page History

« Previous Version 194 Next »

import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate import com.atlassian.applinks.api.ApplicationLinkResponseHandler import com.atlassian.applinks.api.ApplicationLinkService import com.atlassian.applinks.api.application.jira.JiraApplicationType import com.atlassian.sal.api.component.ComponentLocator import com.atlassian.sal.api.net.Request import com.atlassian.sal.api.net.Response as SalResponse import com.atlassian.sal.api.net.ResponseException import com.atlassian.confluence.user.AuthenticatedUserThreadLocal import groovy.json.JsonSlurper import groovy.json.JsonOutput import groovy.transform.BaseScript import javax.ws.rs.core.MultivaluedMap import javax.ws.rs.core.Response import java.net.URLEncoder @BaseScript CustomEndpointDelegate delegate /* MEDIQ V46.1 - unified Confluence DC proxy; preserves original endpoint paths and contracts. * INSTALL: Replace the THREE existing Confluence scripts defining: * mediqGateway*, mediqMaintenanceProxy*, mediqUserFaultProxy* with THIS ONE script. * Never install alongside them: duplicate route registration is ambiguous. * Existing Jira endpoints remain in Jira. Authenticated AppLink must impersonate user. */ def respondMediq = { int status, Object obj -> Response.status(status).type('application/json; charset=UTF-8').entity(JsonOutput.toJson(obj)).build() } def invokeMediq = { String path, String method, String body, int maximum, boolean normalizeId, String operation -> try { // Resolve the actual Confluence request principal, not SAL remoteUserKey. // Do not trust an identity sent by the browser or fall back to anonymous access. def currentUser = AuthenticatedUserThreadLocal.get() if (currentUser == null || !currentUser.name) { return respondMediq(401,[ok:false,message:'نشست کاربری معتبر شناسایی نشد. لطفاً وارد حساب خود شوید و صفحه را دوباره باز کنید.']) } if (method == 'POST') { if ((body ?: '').length() > maximum) return respondMediq(413,[ok:false,message:'حجم درخواست بیش از حد مجاز است.']) def parsed = new JsonSlurper().parseText(body ?: '{}') if (!(parsed instanceof Map)) return respondMediq(400,[ok:false,message:'ساختار درخواست نامعتبر است.']) } def appLinks = ComponentLocator.getComponent(ApplicationLinkService) def link = appLinks?.getPrimaryApplicationLink(JiraApplicationType) if (!link) return respondMediq(503,[ok:false,message:'اتصال سرویس مدیکیو برقرار نشده است.']) def factory = link.createAuthenticatedRequestFactory() def req = factory.createRequest(method == 'GET' ? Request.MethodType.GET : Request.MethodType.POST,path) req.addHeader('Accept','application/json, text/plain') req.setSoTimeout(90000) if (method == 'POST') { req.addHeader('Content-Type','application/json; charset=UTF-8') req.addHeader('X-Atlassian-Token','no-check') req.setRequestBody(body ?: '{}') } Map remote = req.execute(new ApplicationLinkResponseHandler() { @Override Map credentialsRequired(SalResponse response) throws ResponseException { [status:401,body:'',authRequired:true] } @Override Map handle(SalResponse response) throws ResponseException { [status:response.statusCode,body:response.responseBodyAsString ?: '',authRequired:false] } }) int status = (remote.status ?: 502) as int if (remote.authRequired) return respondMediq(401,[ok:false,message:'اتصال حساب کاربری به سرویس مدیکیو نیازمند تأیید دسترسی است.']) String raw=(remote.body ?: '').toString() if (normalizeId && status >= 200 && status < 300 && raw.trim() ==~ /^[0-9]+$/) return respondMediq(status,[ok:true,id:raw.trim(),operation:operation]) Object parsed try { parsed=new JsonSlurper().parseText(raw) } catch(Exception ignored) { return respondMediq(status >= 200 && status < 300 ? 502 : status, [ok:false,message:'پاسخ سرویس نامعتبر است.',httpStatus:status]) } return respondMediq(status,parsed) } catch(Exception error) { log.error('MEDIQ UNIFIED PROXY '+method+' '+path.take(140),error) return respondMediq(502,[ok:false,message:'ارتباط با سرویس مدیکیو برقرار نشد.']) } } def apiPrefix = '/rest/scriptrunner/latest/custom/' def kindAllowed = ['groups','titles','models','equipment','metadata','manufacturer','facility', 'supplier','department','ownerDepartment','responsible','recipient', 'accessories','ownerCompany','location'] as Set def readGatewayMediq = { MultivaluedMap qp -> String kind = (qp.getFirst('kind') ?: 'groups').toString() if (!(kind in kindAllowed) && !(kind ==~ /^equipmentRef_[0-9]{1,9}$/)) return respondMediq(400,[ok:false,message:'نوع داده نامعتبر است.']) String limit=(qp.getFirst('limit') ?: '500').toString() String offset=(qp.getFirst('offset') ?: '0').toString() if (!(limit ==~ /^[0-9]{1,4}$/) || !(offset ==~ /^[0-9]{1,8}$/)) return respondMediq(400,[ok:false,message:'صفحه‌بندی نامعتبر است.']) int lim=Math.min(1000,Math.max(1,limit.toInteger())) invokeMediq(apiPrefix+'mediqCatalog?kind='+URLEncoder.encode(kind,'UTF-8')+ '&limit='+lim+'&offset='+offset,'GET',null,0,false,'') } def writeGatewayMediq = { MultivaluedMap qp, String body -> Map routes=[reference:'mediqCreateModelReference',model:'mediqCreateModel', equipment:'mediqCreateEquipment',lifecycle:'mediqOperations'] String operation=(qp.getFirst('operation') ?: '').toString() if (!routes.containsKey(operation)) return respondMediq(400,[ok:false,message:'عملیات نامعتبر است.']) invokeMediq(apiPrefix+routes[operation],'POST',body,3000000,true,operation) } /* KEEP the permission boundary: catalog and write paths are for MEDIQ operators only. */ mediqGateway(httpMethod:'GET',groups:['mediq-managers','mediq-experts']) { MultivaluedMap qp,String ignored -> readGatewayMediq(qp) } mediqGatewayWrite(httpMethod:'POST',groups:['mediq-managers','mediq-experts']) { MultivaluedMap qp,String body -> writeGatewayMediq(qp,body) } /* Maintenance users retain server-side project permission checks. */ mediqMaintenanceProxy(httpMethod:'GET') { MultivaluedMap qp,String ignored -> String action=(qp.getFirst('action') ?: 'overview').toString() String type=(qp.getFirst('type') ?: '').toString() if (!(action ==~ /^[a-z][a-z0-9.]{0,39}$/) || type.length()>100) return respondMediq(400,[ok:false,message:'پارامتر نامعتبر است.']) String path=apiPrefix+'mediqMaintenance?action='+URLEncoder.encode(action,'UTF-8') if(type) path+='&type='+URLEncoder.encode(type,'UTF-8') invokeMediq(path,'GET',null,0,false,'') } mediqMaintenanceProxyWrite(httpMethod:'POST') { MultivaluedMap qp,String body -> invokeMediq(apiPrefix+'mediqMaintenanceWrite','POST',body,20000,false,'') } /* Self-service: on Jira backend, access is restricted to the authenticated reporter. */ mediqUserFaultProxy(httpMethod:'GET') { MultivaluedMap qp,String ignored -> String action=(qp.getFirst('action') ?: 'list').toString() String key=(qp.getFirst('key') ?: '').toString() if (!(action in ['list','detail']) || (key && !(key ==~ /^MED-[0-9]{1,12}$/))) return respondMediq(400,[ok:false,message:'پارامتر نامعتبر است.']) String path=apiPrefix+'mediqUserFault?action='+URLEncoder.encode(action,'UTF-8') if(key)path+='&key='+URLEncoder.encode(key,'UTF-8') invokeMediq(path,'GET',null,0,false,'') } mediqUserFaultProxyWrite(httpMethod:'POST') { MultivaluedMap qp,String body -> invokeMediq(apiPrefix+'mediqUserFaultWrite','POST',body,12000,false,'') }