U
    ô‰Vb |  ã                   @   sÐ   d Z dZdZddlZddlZddlmZ ddlmZm	Z	m
Z
mZmZmZmZmZmZmZ ddlmZ ddlmZmZmZmZ dd	lmZmZmZmZmZ dd
lm Z  ddl!m"Z" ddl#m$Z$ G dd„ deƒZ%dS )zCopyright 2021, 3LizzGPL version 3zinfo@3liz.orgé    N)ÚDict)
ÚQgsDistanceAreaÚQgsExpressionÚQgsExpressionContextÚQgsExpressionContextUtilsÚ
QgsFeatureÚQgsFeatureRequestÚ	QgsFieldsÚQgsJsonExporterÚQgsJsonUtilsÚ
QgsProject)Ú
QTextCodec)ÚQgsRequestHandlerÚQgsServerRequestÚQgsServerResponseÚ
QgsService)Úfind_vector_layerÚget_lizmap_groupsÚget_lizmap_user_loginÚget_server_fidÚwrite_json_response)ÚExpressionServiceError)ÚLogger)Úto_boolc                   @   s¼   e Zd Zedœdd„Zedœdd„Zeeeddœdd	„Z	e
eeef eedd
œdd„ƒZe
eeef eedd
œdd„ƒZe
eeef eedd
œdd„ƒZe
eeef eedd
œdd„ƒZdS )ÚExpressionService)Úreturnc                 C   s   dS )z Service name
        Ú
EXPRESSION© ©Úselfr   r   ú</var/qgis-server/plugins/lizmap/server/expression_service.pyÚname,   s    zExpressionService.namec                 C   s   dS )z Service version
        z1.0.0r   r   r   r   r    Úversion1   s    zExpressionService.versionN)ÚrequestÚresponseÚprojectr   c              
   C   s~  t ||ƒ}t|ƒ}t|ƒ}| ¡ }||d< t|ƒ|d< | |¡ | ¡ }zÂ| dd¡ ¡ }	zt	| 
¡ ƒ ¡  W n& tk
r”   tdd |	¡dƒ‚Y nX |	dkr®|  |||¡ nZ|	d	krÆ|  |||¡ nB|	d
krÞ|  |||¡ n*|	dkrö|  |||¡ ntdd |	¡dƒ‚W nn tk
r8 }
 z|
 |¡ W 5 d}
~
X Y nB tk
rx } z"t |¡ tddƒ}
|
 |¡ W 5 d}~X Y nX dS )z( Execute a 'EXPRESSION' request
        Úlizmap_userÚlizmap_user_groupsÚREQUESTÚ úBad request errorzInvalid POST DATA for '{}'é  ZEVALUATEZREPLACEEXPRESSIONTEXTZGETFEATUREWITHFORMSCOPEZVIRTUALFIELDSz…Invalid REQUEST parameter: must be one of 'Evaluate', 'ReplaceExpressionText', 'GetFeatureWithFormScope', 'VirtualFields'; found '{}'NzInternal server errorzInternal 'lizmap' service error)r   r   r   ÚcustomVariablesÚlistÚsetCustomVariablesÚ
parametersÚgetÚupperÚbytesÚdataÚdecodeÚ	Exceptionr   ÚformatÚevaluateÚreplace_expression_textÚget_feature_with_form_scopeÚvirtualFieldsÚformatResponser   Úlog_exception)r   r#   r$   r%   Zrequest_handlerÚgroupsÚ
user_loginÚ
custom_varÚparamsZreqparamÚerrÚer   r   r    ÚexecuteRequest<   sN    

ý
ÿü

z ExpressionService.executeRequest)r@   r$   r%   r   c               
   C   s  t ƒ }|  dd¡}|s"tdddƒ‚t||ƒ}|sBtdd |¡dƒ‚|  dd¡}|sx|  dd¡}|sntdd	dƒ‚d
 |¡}zt |¡}W n< tk
rÂ   | d |t	 
¡ ¡¡ tdd |¡dƒ‚Y nX tƒ }	|	 t ¡ ¡ |	 t |¡¡ |	 t |¡¡ tƒ }
|
 | ¡ | ¡ ¡ |
 | ¡ ¡ i }g }g }t|tƒrBt|ƒ}nt|tƒrV| ¡ }|D ]Œ\}}t|ƒ}| |
¡ | | ¡ ¡ |  | !¡ ¡ | "¡ r´| #d || $¡ ¡¡ qZ| %¡ sÒ| #d |¡¡ qZ| &|	¡ |||< qZ|rtdd d '|¡¡dƒ‚|  dd¡}|s6|  dd¡}|r6d| d }dg g ddœ}|sÎi }i }| ¡ D ]H\}}| (|	¡}| )¡ rŒd||< | *¡ ||< nt t+ ,|¡¡||< qZ|d  #|¡ |d  #|¡ t-||ƒ dS zt |¡}W n> tk
r   | d |t	 
¡ ¡¡ tdd |¡dƒ‚Y nX |r<t|tƒr<t.|ƒdkrNtdd |¡dƒ‚d|d ksn|d d dkr€tdd |¡dƒ‚t+ /d | d! t0 1d"¡¡}t+ 2d | d! |t0 1d"¡¡}|sÎtdd# |¡dƒ‚t3| 4¡ ƒ}| 5|¡ t6|  d$¡ƒ}|D ]}t7|ƒ}| 8| 9¡ ¡ | 4¡ D ].}| :¡ }| ;|¡d%kr| <||| ¡ q|r`|	 t =|¡¡ |	 >|¡ |	 ?| 4¡ ¡ i }i }| ¡ D ]d\}}|r | &|	¡ | (|	¡}| )¡ rÊd||< | *¡ ||< n t t+ ,|¡¡||< | @¡ ||< qˆ|d  #|¡ |d  #|¡ qöt-||ƒ dS )&a    Evaluate expressions against layer or features
        In parameters:
            LAYER=wms-layer-name
            EXPRESSION=An expression to evaluate
            or
            EXPRESSIONS=["first expression", "second expression"]
            or
            EXPRESSIONS={"key1": "first expression", "key2": "second expression"}
            // optionals
            FEATURE={"type": "Feature", "geometry": {}, "properties": {}}
            or
            FEATURES=[{"type": "Feature", "geometry": {}, "properties": {}}, {"type": "Feature", "geometry": {},
            "properties": {}}]
            FORM_SCOPE=boolean to add formScope based on provided features
        ÚLAYERr)   r*   z8Invalid 'Evaluate' REQUEST: LAYER parameter is mandatoryr+   z3Invalid LAYER parameter for 'Evaluate': {} providedZEXPRESSIONSr   zLInvalid 'Evaluate' REQUEST: EXPRESSION or EXPRESSIONS parameter is mandatoryú["{}"]z)JSON loads expressions '{}' exception:
{}z@Invalid 'Evaluate' REQUEST: EXPRESSIONS '{}' are not well formedúError "{}": {}úExpression not valid "{}"z&Invalid EXPRESSIONS for 'Evaluate':
{}Ú
ÚFEATURESÚFEATUREú[ú]Úsuccessr   ©ÚstatusÚresultsÚerrorsÚfeaturesNrP   rQ   ú&JSON loads features '{}' exception:
{}ú=Invalid 'Evaluate' REQUEST: FEATURES '{}' are not well formedÚtypeÚFeatureú_Invalid 'Evaluate' REQUEST: FEATURES '{}' are not well formed: type not defined or not Feature.ú){ "type": "FeatureCollection","features":ú}úUTF-8zGInvalid FEATURES for 'Evaluate': not GeoJSON features array provided
{}Ú
FORM_SCOPEéÿÿÿÿ)Ar   r0   r   r   r6   ÚjsonÚloadsr5   ÚcriticalÚ	tracebackÚ
format_excr   ÚappendScoper   ÚglobalScopeÚprojectScopeÚ
layerScoper   ÚsetSourceCrsÚcrsÚtransformContextÚsetEllipsoidÚ	ellipsoidÚ
isinstancer-   Ú	enumerateÚdictÚitemsr   ÚsetGeomCalculatorÚsetDistanceUnitsÚdistanceUnitsÚsetAreaUnitsÚ	areaUnitsÚhasParserErrorÚappendÚparserErrorStringÚisValidÚprepareÚjoinr7   ÚhasEvalErrorÚevalErrorStringr   ÚencodeValuer   ÚlenÚstringToFieldsr   ÚcodecForNameÚstringToFeatureListr	   ÚfieldsÚextendr   r   ÚsetGeometryÚgeometryr!   ÚindexOfÚsetAttributeÚ	formScopeÚ
setFeatureÚ	setFieldsÚ
expression) r@   r$   r%   ÚloggerÚ
layer_nameÚlayerZexpressionsrŠ   Zexp_jsonÚexp_contextÚdaÚexp_mapÚexp_parser_errorsZ	exp_itemsÚkrB   ÚexprR   ÚfeatureÚbodyÚresultÚerrorÚvalueÚgeojsonÚfeature_fieldsÚfeature_listÚfeat_fieldsÚadd_form_scopeÚfÚfeatÚfieldÚ
field_namer   r   r    r7   o   sB   ý
ýý
ÿý





ýü


ÿý
 ý ÿü
þ
ýý






zExpressionService.evaluatec              
   C   s  t ƒ }|  dd¡}|s"tdddƒ‚t||ƒ}|sBtdd |¡dƒ‚|  dd¡}|sx|  dd¡}|sntdd	dƒ‚d
 |¡}zt |¡}W n< tk
rÂ   | d |t	 
¡ ¡¡ tdd |¡dƒ‚Y nX |  dd¡}	|	sð|  dd¡}
|
rðd|
 d }	tƒ }| t ¡ ¡ | t |¡¡ | t |¡¡ tƒ }| | ¡ | ¡ ¡ | | ¡ ¡ i }g }t|tƒrjt|ƒ}nt|tƒr~| ¡ }|D ]\}}|||< q‚dg g ddœ}|	s i }| ¡ D ],\}}t |||¡}t t |¡¡||< q¶|d   |¡ t!||ƒ dS zt |	¡}W n> tk
rL   | d |	t	 
¡ ¡¡ tdd |	¡dƒ‚Y nX |rnt|tƒrnt"|ƒdkr€tdd |	¡dƒ‚d|d ks |d d dkr²tdd |	¡dƒ‚t #d|	 d t$ %d¡¡}t &d|	 d |t$ %d¡¡}|s tdd |	¡dƒ‚t'| (¡ ƒ}| )|¡ t*|  d¡ƒ}|D ]Ê}t+|ƒ}| ,| -¡ ¡ | (¡ D ].}| .¡ }| /|¡d krJ| 0||| ¡ qJ|r| t 1|¡¡ | 2|¡ | 3| (¡ ¡ i }| ¡ D ],\}}t |||¡}t t |¡¡||< q´|d   |¡ q(t!||ƒ dS )!aÚ   Replace expression texts against layer or features

        In parameters:
            LAYER=wms-layer-name
            STRING=A string with expression between [% and %]
            or
            STRINGS=["first string with expression", "second string with expression"]
            or
            STRINGS={"key1": "first string with expression", "key2": "second string with expression"}
            // optionals
            FEATURE={"type": "Feature", "geometry": {}, "properties": {}}
            or
            FEATURES=[{"type": "Feature", "geometry": {}, "properties": {}}, {"type": "Feature", "geometry": {},
            "properties": {}}]
            FORM_SCOPE=boolean to add formScope based on provided features
        rD   r)   r*   zEInvalid 'ReplaceExpressionText' REQUEST: LAYER parameter is mandatoryr+   z@Invalid LAYER parameter for 'ReplaceExpressionText': {} providedZSTRINGSÚSTRINGzQInvalid 'ReplaceExpressionText' REQUEST: STRING or STRINGS parameter is mandatoryrE   z%JSON loads strings '{}' exception:
{}zIInvalid 'ReplaceExpressionText' REQUEST: STRINGS '{}' are not well formedrI   rJ   rK   rL   rM   r   rN   rP   NrS   rT   rU   rV   rW   rX   rY   rZ   zTInvalid FEATURES for 'ReplaceExpressionText': not GeoJSON features array provided
{}r[   r\   )4r   r0   r   r   r6   r]   r^   r5   r_   r`   ra   r   rb   r   rc   rd   re   r   rf   rg   rh   ri   rj   rk   r-   rl   rm   rn   r   ZreplaceExpressionTextr   r|   ru   r   r}   r~   r   r   r€   r	   r   r‚   r   r   rƒ   r„   r!   r…   r†   r‡   rˆ   r‰   )r@   r$   r%   r‹   rŒ   r   ÚstringsZ
the_stringZstr_jsonrR   r”   rŽ   r   Zstr_mapZ	str_itemsr’   Úsr•   r–   r˜   r™   rš   r›   rœ   r   rž   rŸ   r    r¡   r   r   r    r8   I  s   ý
ýý
ÿý

ü
ÿý
 ý ÿü
þ
ýÿü


z)ExpressionService.replace_expression_textc              
   C   sp  t ƒ }|  dd¡}|s"tdddƒ‚t||ƒ}|sBtdd |¡dƒ‚|  dd¡}|s^tdddƒ‚|  d	d¡}|sztdd
dƒ‚zt |¡}W n< tk
rÄ   | d |t	 
¡ ¡¡ tdd |¡dƒ‚Y nX |rÔt|tƒsætdd |¡dƒ‚d|ksü|d dkrtdd |¡dƒ‚t |t d¡¡}	t ||	t d¡¡}
|
sLtdd |¡dƒ‚t|
ƒdkrltdd |¡dƒ‚|
d }tƒ }| t ¡ ¡ | t |¡¡ | t |¡¡ | t |¡¡ tƒ }| | ¡ | ¡ ¡ | | ¡ ¡ t |ƒ}| !|¡ | "| #¡ ¡ | $| %¡ ¡ | &¡ r0tdd || '¡ ¡dƒ‚| (¡ sLtdd |¡dƒ‚| )|¡ t*||ƒ}t+|  d¡ƒ}|s€| ,t*j-¡ | .¡ }dd„ |D ƒ}| /¡ }dd„ |  dd¡ 0d¡D ƒ}|D ]}| 1| 2|¡¡ q¾| 3d¡ | 4dd¡ | 5d¡ | 6¡  t7|ƒ}|r| 8|¡ d}| 9|¡D ]<}|d  t:||ƒ }| 5|| ;|i |¡ ¡ | 6¡  d!}q$| 5d"¡ d#S )$aa   Get filtered features with a form scope

        In parameters:
            LAYER=wms-layer-name
            FILTER=An expression to filter layer
            FORM_FEATURE={"type": "Feature", "geometry": {}, "properties": {}}
            // optionals
            FIELDS=list of requested field separated by comma
            WITH_GEOMETRY=False
        rD   r)   r*   zGInvalid 'GetFeatureWithFormScope' REQUEST: LAYER parameter is mandatoryr+   z7Invalid LAYER parameter for 'VirtualField': {} providedÚFILTERzHInvalid 'GetFeatureWithFormScope' REQUEST: FILTER parameter is mandatoryZFORM_FEATUREzNInvalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE parameter is mandatoryz*JSON loads form feature '{}' exception:
{}zPInvalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formedrU   rV   zrInvalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formed: type not defined or not Feature.rZ   zSInvalid FORM_FEATURE for 'GetFeatureWithFormScope': not GeoJSON feature provided
{}é   r   z<Invalid FILTER for 'GetFeatureWithFormScope': Error "{}": {}zGInvalid FILTER for 'GetFeatureWithFormScope': Expression not valid "{}"ÚWITH_GEOMETRYc                 S   s   g | ]}|‘qS r   r   ©Ú.0Úir   r   r    Ú
<listcomp>  s     zAExpressionService.get_feature_with_form_scope.<locals>.<listcomp>c                 S   s   g | ]}|r|  ¡ ‘qS r   ©Ústrip©r©   rž   r   r   r    r«   ‘  s      ÚFIELDSú,éÈ   úContent-Typeúapplication/jsonú*{ "type": "FeatureCollection","features":[Ú.ú,
ú]}N)<r   r0   r   r   r6   r]   r^   r5   r_   r`   ra   rk   rm   r   r~   r   r   r€   r}   r   rb   r   rc   rd   re   r‡   r   rf   rg   rh   ri   rj   r   ro   rp   rq   rr   rs   rt   rv   rw   rx   r   r   ÚsetFlagsÚ
NoGeometryÚprimaryKeyAttributesr   Úsplitru   r…   ÚsetStatusCodeÚ	setHeaderÚwriteÚflushr
   ÚsetAttributesÚgetFeaturesr   ÚexportFeature)r@   r$   r%   r‹   rŒ   r   Z
exp_filterZform_featurer™   Zform_feature_fieldsZform_feature_listZ	form_featrŽ   r   Zexp_fÚreqÚ	with_geomÚpk_attributesÚattribute_listr   Úr_fieldsrž   Újson_exporterÚ	separatorrŸ   Úfidr   r   r    r9   ÿ  s   ý
ýýýÿÿü
ÿüÿþüþýÿüÿü

 ÿü
ÿü





z-ExpressionService.get_feature_with_form_scopec              
   C   s  t ƒ }|  dd¡}|s"tdddƒ‚t||ƒ}|sBtdd |¡dƒ‚|  dd¡}|s^tdddƒ‚zt |¡}W n< tk
r¨   | d	 |t	 
¡ ¡¡ tdd
 |¡dƒ‚Y nX t|tƒsÆtdd
 |¡dƒ‚tƒ }| t ¡ ¡ | t |¡¡ | t |¡¡ tƒ }	|	 | ¡ | ¡ ¡ |	 | ¡ ¡ i }
g }| ¡ D ]Œ\}}t|ƒ}| |	¡ | | ¡ ¡ | | ¡ ¡ |  ¡ rŒ| !d || "¡ ¡¡ q2| #¡ sª| !d |¡¡ q2| $|¡ ||
|< q2|rÞtdd d %|¡¡dƒ‚t&ƒ }|  dd¡}|rvt|ƒ}| |	¡ | | ¡ ¡ | | ¡ ¡ |  ¡ rFtdd || "¡ ¡dƒ‚| #¡ sbtdd |¡dƒ‚| $|¡ t&||ƒ}t'|  d¡ƒ}|s–| (t&j)¡ | *¡ }dd„ |D ƒ}| +¡ }dd„ |  dd¡ ,d¡D ƒ}|D ]}| !| -|¡¡ qÔ| .d¡ | /dd¡ | 0d¡ | 1¡  t2|ƒ}|r,| 3|¡ d}| 4|¡D ]º}|d t5||ƒ }i }| 6|¡ | 7| +¡ ¡ i }|
 ¡ D ]T\}}| 8|¡}| 9¡ rªd||< | :¡ ||< n t t; <|¡¡||< | =¡ ||< qx| 0|| >|||¡ ¡ | 1¡  d}q:| 0d¡ dS ) aY   Get virtual fields for features

        In parameters:
            LAYER=wms-layer-name
            VIRTUALS={"key1": "first expression", "key2": "second expression"}
            // optionals
            FILTER=An expression to filter layer
            FIELDS=list of requested field separated by comma
            WITH_GEOMETRY=False
        rD   r)   r*   z=Invalid 'VirtualFields' REQUEST: LAYER parameter is mandatoryr+   z8Invalid LAYER parameter for 'VirtualFields': {} providedZVIRTUALSz@Invalid 'VirtualFields' REQUEST: VIRTUALS parameter is mandatoryz&JSON loads virtuals '{}' exception:
{}zBInvalid 'VirtualFields' REQUEST: VIRTUALS '{}' are not well formedrF   rG   z(Invalid VIRTUALS for 'VirtualFields':
{}rH   r¥   z1Invalid FILTER for 'VirtualFields' Error "{}": {}z<Invalid FILTER for 'VirtualFields' Expression not valid "{}"r§   c                 S   s   g | ]}|‘qS r   r   r¨   r   r   r    r«   %  s     z3ExpressionService.virtualFields.<locals>.<listcomp>c                 S   s   g | ]}|r|  ¡ ‘qS r   r¬   r®   r   r   r    r«   '  s      r¯   r°   r±   r²   r³   r´   rµ   Nr¶   r·   )?r   r0   r   r   r6   r]   r^   r5   r_   r`   ra   rk   rm   r   rb   r   rc   rd   re   r   rf   rg   rh   ri   rj   rn   r   ro   rp   rq   rr   rs   rt   ru   rv   rw   rx   ry   r   r   r¸   r¹   rº   r   r»   r…   r¼   r½   r¾   r¿   r
   rÀ   rÁ   r   rˆ   r‰   r7   rz   r{   r   r|   rŠ   rÂ   )r@   r$   r%   r‹   rŒ   r   ZvirtualsZvir_jsonrŽ   r   r   r‘   r’   rB   r“   rÃ   Z
req_filterZreq_exprÄ   rÅ   rÆ   r   rÇ   rž   rÈ   rÉ   rŸ   rÊ   ZextrarQ   r˜   r   r   r    r:   ¨  sü    ý
ýýÿý

ý



ý

 ÿü
ý








zExpressionService.virtualFields)Ú__name__Ú
__module__Ú__qualname__Ústrr!   r"   r   r   r   rC   Ústaticmethodr   r7   r8   r9   r:   r   r   r   r    r   *   s2    ÿ3 Z
   ÿ 6
   ÿ )r   )&Ú__copyright__Ú__license__Ú	__email__r]   r`   Útypingr   Ú	qgis.corer   r   r   r   r   r   r	   r
   r   r   Zqgis.PyQt.QtCorer   Úqgis.serverr   r   r   r   Zlizmap.server.corer   r   r   r   r   Zlizmap.server.exceptionr   Úlizmap.server.loggerr   Úlizmap.server.toolsr   r   r   r   r   r    Ú<module>   s   0