Compare commits
15 Commits
bc31040d81
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5b08aaae2 | ||
|
|
c6d2c068d3 | ||
|
|
5449ab9d4d | ||
|
|
92548920c2 | ||
|
|
7c848bbdb0 | ||
|
|
eb884faea1 | ||
|
|
238ded3f54 | ||
|
|
bb082c8368 | ||
|
|
cda80990c7 | ||
|
|
e32a2a2722 | ||
|
|
240489d330 | ||
|
|
7e2706b04f | ||
|
|
4b52b72266 | ||
|
|
a11535726d | ||
|
|
0cf1160853 |
4
.env
4
.env
@@ -60,8 +60,8 @@ ADMIN_EMAIL=contact@e-cosplay.fr
|
||||
SMIME_PASSPHRASE='KLreLnyR07x5h#3$AC'
|
||||
|
||||
###> SonarQube ###
|
||||
SONARQUBE_URL=https://sn.esy-web.dev
|
||||
SONARQUBE_BADGE_TOKEN=changeme
|
||||
SONARQUBE_URL=https://sn.e-cosplay.fr
|
||||
SONARQUBE_BADGE_TOKEN=sqb_d02e5edca9ef985e356d969f59acbc6bc9cd0f50
|
||||
SONARQUBE_PROJECT_KEY=e-ticket
|
||||
###< SonarQube ###
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ APP_SECRET='$ecretf0rt3st'
|
||||
DATABASE_URL="postgresql://app:secret@pgbouncer:6432/e_ticket?serverVersion=16&charset=utf8"
|
||||
MEILISEARCH_URL=http://meilisearch:7700
|
||||
MEILISEARCH_API_KEY=e_ticket
|
||||
SONARQUBE_URL=https://sn.esy-web.dev
|
||||
SONARQUBE_URL=https://sn.e-cosplay.fr
|
||||
SONARQUBE_BADGE_TOKEN=test
|
||||
SONARQUBE_PROJECT_KEY=e-ticket
|
||||
STRIPE_SK=sk_test_fake
|
||||
|
||||
@@ -116,27 +116,11 @@ jobs:
|
||||
./hadolint docker/php/dev/Dockerfile -f json > hadolint-dev.json || true
|
||||
./hadolint docker/php/prod/Dockerfile -f json > hadolint-prod.json || true
|
||||
|
||||
- name: OWASP Dependency-Check
|
||||
uses: dependency-check/Dependency-Check_Action@main
|
||||
with:
|
||||
project: 'e-ticket'
|
||||
path: '.'
|
||||
format: 'JSON,HTML'
|
||||
args: >
|
||||
--scan composer.lock
|
||||
--scan package.json
|
||||
--out .
|
||||
--disableAssembly
|
||||
--nvdApiKey ${{ secrets.NVD_API_KEY }}
|
||||
continue-on-error: true
|
||||
|
||||
- name: Rename Dependency-Check reports
|
||||
run: |
|
||||
mv dependency-check-report.json dependency-check-report.json 2>/dev/null || true
|
||||
mv dependency-check-report.html dependency-check-report.html 2>/dev/null || true
|
||||
|
||||
- name: SonarQube Scan
|
||||
uses: sonarsource/sonarqube-scan-action@v5
|
||||
with:
|
||||
args: >
|
||||
-Dsonar.host.url=https://sn.e-cosplay.fr
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: https://sn.esy-web.dev
|
||||
SONAR_HOST_URL: https://sn.e-cosplay.fr
|
||||
|
||||
@@ -9,12 +9,24 @@ jobs:
|
||||
deploy:
|
||||
runs_on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup SSH key
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
ssh-keyscan 34.90.187.4 >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Deploy
|
||||
run: ssh bot@34.90.187.4 "cd /var/www/e-ticket && ansible-playbook ansible/deploy.yml -i ansible/hosts.ini --vault-password-file <(echo '${{ secrets.ANSIBLE_VAULT_PASSWORD }}')"
|
||||
- name: Deploy with SSH
|
||||
uses: appleboy/ssh-action@v1.0.0
|
||||
env:
|
||||
VAULT_PASS: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
|
||||
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
|
||||
with:
|
||||
host: ${{ secrets.SSH_HOST }}
|
||||
username: ${{ secrets.SSH_USER }}
|
||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
port: 22
|
||||
envs: VAULT_PASS,DEPLOY_PATH
|
||||
script: |
|
||||
bash -c '
|
||||
set -e
|
||||
cd "$DEPLOY_PATH"
|
||||
VAULT_FILE="$(mktemp)"
|
||||
trap "rm -f \"$VAULT_FILE\"" EXIT
|
||||
printf "%s" "$VAULT_PASS" > "$VAULT_FILE"
|
||||
chmod 600 "$VAULT_FILE"
|
||||
ansible-playbook ansible/deploy.yml -i ansible/hosts.ini --vault-password-file "$VAULT_FILE"
|
||||
'
|
||||
|
||||
@@ -92,25 +92,13 @@ jobs:
|
||||
./hadolint docker/php/dev/Dockerfile -f json > hadolint-dev.json || true
|
||||
./hadolint docker/php/prod/Dockerfile -f json > hadolint-prod.json || true
|
||||
|
||||
- name: OWASP Dependency-Check
|
||||
uses: dependency-check/Dependency-Check_Action@main
|
||||
with:
|
||||
project: 'e-ticket'
|
||||
path: '.'
|
||||
format: 'JSON,HTML'
|
||||
args: >
|
||||
--scan composer.lock
|
||||
--scan package.json
|
||||
--out .
|
||||
--disableAssembly
|
||||
continue-on-error: true
|
||||
|
||||
- name: SonarQube Scan
|
||||
uses: sonarsource/sonarqube-scan-action@v5
|
||||
with:
|
||||
args: >
|
||||
-Dsonar.host.url=https://sn.e-cosplay.fr
|
||||
-Dsonar.qualitygate.wait=true
|
||||
-Dsonar.scm.forceReloadAll=true
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: https://sn.esy-web.dev
|
||||
SONAR_HOST_URL: https://sn.e-cosplay.fr
|
||||
|
||||
@@ -157,8 +157,8 @@
|
||||
file:
|
||||
path: "/var/www/e-ticket/public/uploads/{{ item }}"
|
||||
state: directory
|
||||
owner: "1000"
|
||||
group: "1000"
|
||||
owner: "1001"
|
||||
group: "1001"
|
||||
mode: "0755"
|
||||
recurse: true
|
||||
loop:
|
||||
@@ -168,8 +168,8 @@
|
||||
file:
|
||||
path: /var/www/e-ticket/var/payouts
|
||||
state: directory
|
||||
owner: "1000"
|
||||
group: "1000"
|
||||
owner: "1001"
|
||||
group: "1001"
|
||||
mode: "0755"
|
||||
|
||||
- name: Ensure Caddy sites directory exists
|
||||
|
||||
@@ -181,7 +181,7 @@ services:
|
||||
retries: 5
|
||||
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:latest
|
||||
image: getmeili/meilisearch:v1.40.0
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
|
||||
@@ -17,7 +17,7 @@ STRIPE_MODE=live
|
||||
SMIME_PASSPHRASE='{{ smime_passphrase }}'
|
||||
MEILISEARCH_URL=http://meilisearch:7700
|
||||
MEILISEARCH_API_KEY={{ meilisearch_api_key }}
|
||||
SONARQUBE_URL=https://sn.esy-web.dev
|
||||
SONARQUBE_URL=https://sn.e-cosplay.fr
|
||||
SONARQUBE_BADGE_TOKEN={{ sonarqube_badge_token }}
|
||||
SONARQUBE_PROJECT_KEY=e-ticket
|
||||
OAUTH_KEYCLOAK_CLIENT_ID=e-ticket
|
||||
|
||||
@@ -1,162 +1,162 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
36656162363566643931323630643533623133653261396132303936353762623038646335343834
|
||||
3362613463376536633164356262333335653966386435320a323738666438613937663739346534
|
||||
65666633633839643830666366623630636463666538313535666130623264393464393736323730
|
||||
3035623566333436370a613535373861366334343238356236633634326330653530383762316237
|
||||
37316439313262323437633937356133653333366334333533343837323865326666306461643231
|
||||
32656134613965326433663338356230366338653232343636333261366136623332353536326261
|
||||
37386138393039616333313539366538333962656161353031303432663638306334393332623063
|
||||
37653937643961333666653738613731383230623530663134396236353435313566353135376566
|
||||
65373830613433633563636334376135376530316261633930313466666461323837373031613735
|
||||
35386263383766666664366536393537303935373236666661656566346563633763393763383663
|
||||
37343030376666346365363039666234346537626134323232636364373763623332656435343533
|
||||
32346436393666383431613839373238623135336635613062373663623264366530666662353831
|
||||
36656536363832663661396331376264376235616231313937393039303634383361313038366361
|
||||
31653635666537326234323264313239616662636639656564343830303964626464616430303535
|
||||
39633864356165653735623537323438373739306566646165383436313739326662653361313038
|
||||
65383038393730313235636166363832303537353037613831653335373166663236346439313139
|
||||
32393537356630666538373237666533376661636638663433653038396331373532636364326333
|
||||
35336530346538636330646462303266656234306461613430623638623865313463376530646162
|
||||
37396436386665336266306132386164393730623836636436663831343662373732653962393936
|
||||
30303664373431643630383131393431643134383166613831363564343066653862316262316464
|
||||
39623432303565393565613034383562306434306334323433303535623666323030363265646634
|
||||
33363737353531653864356439646364313432373130363237323363663061636536363262323938
|
||||
64366530663466636239666336323963326336616233333539333534356631396466366462333130
|
||||
30616135363434386637643138323834386331653166623762356561653237613334333132303739
|
||||
61393732323735623163316134306138323936373132303934303530313431333532356634633530
|
||||
35343138376563323039343030613337396165633664353331663564636264376665616166323831
|
||||
30326566353438363438363962346332643736636163306161313239333561613831303438663332
|
||||
61346535353630643664626331303530353732393962333265333763386139623931356433373236
|
||||
39313130353538316232366533343166616332626563626462343730643934636531343364366131
|
||||
66633265663537613532383333343163313232326332333831633563616338353663623133666464
|
||||
33643837386637333335633065633865313366363236643337643034306539306661333733623231
|
||||
39366638386366313333393431636265633563653238346638333536643835383335363166633662
|
||||
34323534326533316238356439666330653532363663303464353965616262356333316466383262
|
||||
30613163323436343130366230336231613366366533343662313962306466353039666665656362
|
||||
39666164313835313266373966353037623064383863623831373739303431653330353164646534
|
||||
32326435343831636631663634396531383237313663313737343238353733333962626631313262
|
||||
62323165653133383238333162643539646237303466666533393037643262656161363338633665
|
||||
38323239346662373566336139636164333434316362386365363539383563613861666337653532
|
||||
36346332303530323365363965656263313333613530613637373761643434643336303534393633
|
||||
35353738303766646165663239303030373966343066626233383234313535626366636563326239
|
||||
33656433353032613036653732656535613837343130653939623461306261316263666466356665
|
||||
39666162623030666637666236653939383836316633323532616563656461653438623064633139
|
||||
30656635383862666361336361343238656130313263646662666534353737643964663136623133
|
||||
39616638613037313936636235346438643533646437633263616238373637356631633534656662
|
||||
39366632653430393037643437373232306631326234646463303432616337643833373330656661
|
||||
31363334653665303431663366626265623337333631396463353636313637663665346565353239
|
||||
63663334396531663931633738343733373061633335343932356665396331316564373365363437
|
||||
39373762653462326433303534323732656133353139303536623761623834333532303630326131
|
||||
34383465633239326333373562626539386262363836656237373136653566323631333334323139
|
||||
33336239306263636232343939653764373037346566333635396234393438616637633533343066
|
||||
61383961363536326337333161376331373838393331333237383261343534336562646234643662
|
||||
32633338386336643130366532303638383338343766333831643336373663383762356236616535
|
||||
35666134653531666161383537663331316633613335386134356362363336666530666534383638
|
||||
63386437303030316135306365613038316465663137346531343735613637363535653166303562
|
||||
37353265303561363866353537353062653363383066313065356639366562386461383931666638
|
||||
38646335343037663939323965303562643662313837356536326439346466333432636662333233
|
||||
62393763373736313832383534653435333861663738633931356236616434373335636233386431
|
||||
30633834626665396465383337333061306561663230653933363766623566646462623835383539
|
||||
64646564313463313430356161343431633566656233623036383337623363363230383835363639
|
||||
37363039346366623865616565373963363261643566323436323361306230363438626430333763
|
||||
66656531343431323865303036333538303230326632316662633232316164313137373039613639
|
||||
66326462333237303466303133316330636431376466623937626631393933343439633266353566
|
||||
65393163383861623566373063643330356336373863616234666364323963373662316138326439
|
||||
35363430346331383631633734653664323863636564323037333265623738383866643431353634
|
||||
64636533383933666461336462663939653032306631333636323538613139373462373837646165
|
||||
35653239323234383132623531633736333139366365323233623036393935623635373239626463
|
||||
64373162373166353666613533646665353036666639353730303037333934313135343964613933
|
||||
62323433313237356262366230633830616630393133366465326133333339393061323961623031
|
||||
30303739383235316365636134343165323632393730653437353564366631636663623837663966
|
||||
39376366303630656339386333323863356365323965656539336530643361663363303366643230
|
||||
32333638653665373363653235623264393766616636336534363935353238366431623761666361
|
||||
38303364363436326665643930393734616638393836623135316239396364396266613432353863
|
||||
33643135313931636463306265343830343536376430666437363466613431326235613832613837
|
||||
33396265616562386534393338373862353237323964353137643334386431663537653039643462
|
||||
30366432373632366135646438313632303838623939336539333639363530346536386436633362
|
||||
62383339363163613066663131326566633464646136616533383633313261383339333965313338
|
||||
66316236343231306431653237646263306539353962373762393739663364626438646439326534
|
||||
61383135356635633661653561313564303433393438616136353637656666373431343537656139
|
||||
35383433386438396237356332373937643064383938306631623735636330313335656562306466
|
||||
62633961656631353463633062313031356566373336396130316330353634336661613433613462
|
||||
61653261383732353565613033353466616264653835396363303539313066333839323930633631
|
||||
36613035363434646131653730323965333634396437353862656162356266326165393036323736
|
||||
35386338326538343162396662383932386436613234393366623035633638346430393639336133
|
||||
33376138386564363361353233323764353362313931396538633539656464623439613464386436
|
||||
32383334613635636131363966393536343738396332653961373362626134333366353939663366
|
||||
62613039366161633539393961313364396264363532653139306631376439663335393635623135
|
||||
38303737336631636661366236636464383363663261363164616538383162353962323132366433
|
||||
61653937343438363466363134343238306330313036336635626464383634646638616233393361
|
||||
32623232646365363661363839633137356633666339376437346532393330626362373765393265
|
||||
35643931383266326464306439353034323334393261373537393765333935356663616361353466
|
||||
39643037363435646663336262303739623438343062633465653835333161316439383732666265
|
||||
33376133363238663134393334326333643337383033333538326139373530353637616334633162
|
||||
34323933393764343930356332666534626133363562653636396662383663666130613639333338
|
||||
34666362656165623435653836316662323538636334323231663061336237323737653163323134
|
||||
33383462306262366163326639303564653139396232373563623332633834346537653362633430
|
||||
63663938323735653034363862663465373232376437346637646539303266353034396331306538
|
||||
66393332336431383866646535306162313531373761396562356564333033376635303165363038
|
||||
66383735386432616632366163623365623265366130306562386338623165613863663038613664
|
||||
33646165633861323964376232326134323833373066663934633565663034333335616437303164
|
||||
61323935666231623638623139626662396437303534356438633438313461613566643736323032
|
||||
34326233643637613238613433393832373938643036326565633935363661396333613038356364
|
||||
33316639303238616662313932386135633233623839376437613238346530663061613738306532
|
||||
37613565626362326435646232303830613438393436613836366139356431343761333331623936
|
||||
61333965336230386638656462636130393364393432663464383039373631303537346662383035
|
||||
30343737336235316561663763653333373161393633383734376231633537373335623833386334
|
||||
33383464346335383539343630343965366436326261366530313231633132626137363332656233
|
||||
33356637653132383463613733366465303338336633663865623762343462616561623039386166
|
||||
31663463303439316161376164663561353263356339623931356263336132313765646466353166
|
||||
39363530323236623364396539383836336138653863353631393933306339303563656638373766
|
||||
61343565656232386534646530633265396465636362393434393761363536333237366566653332
|
||||
32613730623165646333356362653036316363656661306330356162336264356563343766373263
|
||||
36393131356335306463623262366133613166346234633661376234336239353963343666313166
|
||||
34613163643963303763616533333461323833336532373538356536366634613436393231303630
|
||||
31373966386563343939656566376435356630333833643563323162633236353932306636386633
|
||||
35636532323264626461346139306636373361356639373739363934323838623933653438363839
|
||||
32636331633236383536656631346437316263656662623864663733366563323234636364656461
|
||||
61626534323934353931313630363266306131613239656462393331323930656239646464666137
|
||||
65363261376133643331666530323437653166633461373162363439316630346531616534316434
|
||||
35393162646332323531653830623632393534643132323730396637633630346461343665393565
|
||||
37623165393235346532626634363531653561666634356534306637666231613337373665393838
|
||||
63326133613531666661663636326135356439306532663138336438633938636534613035343865
|
||||
34656536366261306430656432373566396363353735366432333430396431366131663037653331
|
||||
32396532613664353436333735636431326134396335633832356334323634366532663032383038
|
||||
61306636646261353763393732366161323230326233336535613162666331386631663938633032
|
||||
34393031633063353533333663313030383964353861316162343830316233376435386331633336
|
||||
33613739333231323563666632393831653236313065373266303937393032393931333861326335
|
||||
37343235303065333435633530336231666239636364323737383739323535333939343161666431
|
||||
37323462623133343162376664636338646439386431356662383831366664623864363730303262
|
||||
38663461376662373462643331376464646533633535643230316236383965383966393131643436
|
||||
36656631373630373861623162383666303538623932303963363766343433313735616261306161
|
||||
30353934373763376536396536373663616466643863316132343731353063643439623038633935
|
||||
30363961343863663333353562366630303034386161363731663666633030643132313639316463
|
||||
31363061383535313938656534396433396466623237323962346366353033383231313832643531
|
||||
64633861623831336362343931616265633338623036383332666237653461346330393633666131
|
||||
66386636326536623362656135623037333166633230383163386234393064613165666536626131
|
||||
62623835383236363438653631326336623735326539383538393038333536343961646436653865
|
||||
34616538383763306239366237396138366163656135346438313839396232386237653734393537
|
||||
35386664333330646133343866356234643037356564356364666364306466343639316335633939
|
||||
38623834353936633133326633636464343038323539306631343863353065616338333438633135
|
||||
32343734383063363565396136666139333834366539386165373465326531323137636263303762
|
||||
31623438326464333534383761616637613636373036343038326437313131633634333136643439
|
||||
65393564383736363431373538663039633933646432356166313038383663653065343736336163
|
||||
62363738626433333033646263623661616136396566653536313832653431653663616262383464
|
||||
37636538326231376366343165346533636263363962356162656635616435313236326661346234
|
||||
65393838383431353663303961633634336334656137643230326331316132356365313730346436
|
||||
39356438656534366566313733653632623466333931343434373130343261653962346132656364
|
||||
39326637653334343763346538393836343439653738383161373566626530656430623465363034
|
||||
37636431323335376163663966323836313734643337396464623630653266656133653239383531
|
||||
66626533663130316131616162666361393839316639346564636166383736633639316539383861
|
||||
65666533353166333764666266613338346335313232323137363464383363343836356165333734
|
||||
37363037383466373264326561303161323735613131323534333464393936383663326539376634
|
||||
30393335663865623135656130373161373338666431346539303033313565333534343761633336
|
||||
36383665306534633930386331376664353561336266303330383464363130353539326534306661
|
||||
39613434663131383062616632383138643066303063323739346630343038623764643262326638
|
||||
36613733356537333664363732653534663833646363646661346566323461323239333636666564
|
||||
38323030363139663031633230303062653739386163333638363433663461653161353065323439
|
||||
38316361346232623134326162343262393231333562616437323737353230633734356634306132
|
||||
37316461303037363430366638366330633662643663336637343536393137383837656633313131
|
||||
62393161613261623961663039353934663161373262396234653865643766626432376536373831
|
||||
39346564323263393633326663353731633738363033646539346438663661353666383834313434
|
||||
3663
|
||||
32336666393730636235393866376234353162333531383338333766376461373262336562663539
|
||||
3261346464363536646235623163313738333564343263390a386134303031316135306163363732
|
||||
39313336616264643561643763393033346638313339343635306165653734666262663066666437
|
||||
3366333130373130320a646538383536356331626136353639626638373337643733666232363030
|
||||
62393166633933396532373531383937633935653431313733653932393864396235636363306363
|
||||
31656533623536393265356131373936326633303931646166353530336131356533613761613336
|
||||
32313939363132616539353033333234653131353335373030356633373761663561316336356530
|
||||
33646434633135323265383237363663393861333936393766663737303836306566396636653537
|
||||
31363538383139393065623232663235343238633137666463643566613333353632333961303838
|
||||
61646537366232313538663565643962303635363635626130316161383831646265323939613930
|
||||
30323765383439326432333631373933663637343930313033636338306133646232316233396665
|
||||
39363139326566666366343535633635366261336339626534346433393539333137393261346464
|
||||
32343230376464326437623261343633353638626131666534663861323132346461333339346662
|
||||
62336465646264646535303233346433313733323461346561333337303663653431303633333961
|
||||
62316636356265356438633733663062333435656532376163653162383938386336386636393461
|
||||
35666435343235323439626366366137666539666430616264336433343336373539396332646562
|
||||
62343732356336343436663837616161666666386465643166623035383162343936613862656166
|
||||
66363939393563376466613362363633316564663230646531643932333962373836396362633037
|
||||
32616530366465363637326531653631323136383564323837323431623937623366666339623338
|
||||
65366135363631373535313431306365666661656465643837316661343638313635383564303133
|
||||
30386336383939383462653064666264383865303239616639313338363762336332633239613639
|
||||
30623637626232333137633134336533326136303831353837333339653866366362656162633430
|
||||
32313935326332303038636363663438643966393165613637656166626231336332663035326332
|
||||
66616464663935303130363763313263396266383463393736646463616365626232633066636131
|
||||
63323734313131366365323762326164386639616261353962373965373364666665316539383234
|
||||
33393265653063613166316530656138356138356232303834303036663566313461666531663832
|
||||
66653633643965623039363439303432373131363366363661353866356532353131626336393164
|
||||
33613565396334663366653534353432633231656637353937323031306237663765666266353830
|
||||
37626139636635316561643338346464623832333435383438613335326166356430333238343863
|
||||
33346637646135326430653665346633386532373534666266396365316636623263343861623138
|
||||
33396434326561376136636634316135386132323665323133623039336262343039316533316463
|
||||
33373339633631366130373838353765313537333436613961643333643937363162366439393339
|
||||
37326439653633353065333861313531363034346462353065356661666263353031346634326336
|
||||
37616333666166363862313035383266303031663133363361333539356439373032376430386561
|
||||
66646536376438396561336162333963613365306337656265646430323338396166666231643663
|
||||
35326437663963643735333632306434666463343937613861613931366239633538633163356633
|
||||
33353033353962323930663131313334303563333039316566313965663636383766393239636464
|
||||
38343966353564343830643061383461363664343362626338346563633539656432313433636139
|
||||
61316363303534633938333137636234323137636131356466336430396265323865393435336161
|
||||
34313531663761643533363131383938343830656637373931303535393962333233363835636634
|
||||
61656436336632623030346535626238303135303537633439613763643939333064613162326537
|
||||
38376438626233643463626633623365336232373566633064653131653034336133663838326133
|
||||
36393736653164653730383562346166393265333431363434386466393663633535626562326661
|
||||
34303738353938353162323630623432663639663066326231623335663561386535323831633963
|
||||
62386130613634333730653639613134653031386636326164323732666466383035373539646235
|
||||
34373264323134653539336262616632333263653833653166306665363564333038353834386639
|
||||
61376332373133653431623866373963303432313065383831623937326338323664643464336464
|
||||
63396537386234633464313563666434396130383930303139656339636663326461643861313363
|
||||
33373431393035323165616330353762626231386464313964643466353039366536656638363835
|
||||
33666238323932623662346533616431393162653236323664366461336666336563323464643065
|
||||
34323833663038636639376566343730393238613965323561666132643766306232336132303231
|
||||
38336561633161326330363263303837666636633162643765336364633161383931366264356663
|
||||
63656133323636643832343537303632303866316130626130323265623235363836316637616237
|
||||
39333833343331626465396362373166353634626366356134323831623265613037666463633563
|
||||
33333438343838633438343636316139393865316135623436303463666336396561383662356165
|
||||
33363564393634353061656134366165323539383535643533363333323931333063316564666632
|
||||
61633534393965626264633630343464323764633436656530656639666161613166626533393765
|
||||
64366164393537393464326635363333353232393164636233343531623862663031383264643564
|
||||
34616264633461333063616462636566343539323930303032336338353466303164303366373735
|
||||
35653634643434663561396239353437636136383333653136303964306130643465653266623638
|
||||
64653630386164373162393238363830373533626131363931316536613761346562663364643331
|
||||
31373463623530383232636236383766313231356161306533343238313333366565386338623335
|
||||
34613266386535363861653834613363643038383264323939383738323531353064316563313130
|
||||
30633266323762643537393139616630643934643063346666653831656335333930393430333836
|
||||
32303438356137303433626333646263323632346333303230353736363565623733636432336439
|
||||
63353664396564343662313531646538383638333731623163383838633435353164666337326634
|
||||
36313331336238643365666566633763646462666561643465616239316130656264356166643138
|
||||
61623561386264343239636137626532353562326163343263666664306661323636666236373936
|
||||
38393866613965626133323734326138313866656434373133306330643731353436343264663235
|
||||
61363962323533613463376634323863316164663965623665363039656235353262666137643866
|
||||
35393061613234343435643361313264376335616435613466343362306531393735393864333666
|
||||
63326534306665383334353132393561303536623134326332366230383165643131646139626162
|
||||
66323539323966653636666434656464303566343665666165643461313930343432343861623231
|
||||
34616666303161616531386463636535656161633231313137396332646637353736343338616566
|
||||
61623735306336383165356331326363366238336334383031336662356461316332356431623933
|
||||
33636239353966373731626130353430353564626333643736363366313038303762393432376139
|
||||
65343261653637333530316130316233383462623164643562393138386133343735386564346264
|
||||
65323132616338346439663536333636306261613239313538313239633438646262616337316537
|
||||
30343037393762306232633630626432653763336634653064393939353066396430363730653037
|
||||
39393962356661396338396366373765363530323736643134396561656137336466646130306133
|
||||
64653464376636623637313966613635336638383565393732366164636466643036343130366361
|
||||
65653334623863666165333361306332333137383435383861356366666666626639623962373130
|
||||
64653762623430663061356364316565313662346337663335323664353430616663363335303134
|
||||
35336363623136326439356166636130633336626163343262396430323662356138623131376561
|
||||
36316432313866376236623362376561313366383332653935623433666265643166373836613730
|
||||
33633038666364373033383339656433343335393535313463633330393832336233663663363263
|
||||
33623432613431346239633362663135376532353230366331303237623863623534313338326335
|
||||
37666437613964366337393232313138343135636135396337333665313162303965303764366436
|
||||
65306531343865356436346562613937363731376662393161313264386231653161663434386633
|
||||
37386663323862313039633937393861613634633933366334383737353632363934313230376237
|
||||
61373534383736623665383237303035643133356433336634343466613462643537366139303863
|
||||
32396261623030313935386333623237633037623065616262616536613461613233303264613130
|
||||
33333735323536636532366261656162353561643038323734643832663137623537633831373235
|
||||
35383366353834336461376437326661303237633261616564656637376364373839363637393632
|
||||
35633135333665393662376536376335363866383262656462643232356530663437336537383434
|
||||
66336135333665653130666630386235323030356538636533393761653837653532373863363134
|
||||
31326632306432356639323763383232613462306465633932396665663839366338633734333533
|
||||
32313034383765323661386633633639366464643934616663333030383966633233303934323463
|
||||
65336431633133393765356631616161666631656663396633643635383961393862326435313932
|
||||
31386136363862633835346337643364663463613866323461326362633334663936393039313936
|
||||
38393135323966616635313963336431373131316534383339306531343934363533363264353564
|
||||
38343863366231393164333264383965643935386230653630613238396165613962333866333030
|
||||
61386335306161353033653564336233333066373266326531656138343334653434333432353166
|
||||
37386535326138373461643461323966306663316139666639323432636639346561393961313230
|
||||
34303736656338366236313839653937383539613034613536323834393932616136623636373135
|
||||
33393561303363336433613137333564616566653665626634663533613236633637663964393366
|
||||
66343639393463363461346437626432663333356234373235376632306163613932636339353833
|
||||
37376533613735393866326530323039386566383661326134363062363361363433613030373433
|
||||
64323364313461323037303937306231306439636463383761393630346163303839393737313530
|
||||
33383535303632363362393061633931376330373231636361376334336632393634306433376261
|
||||
62343631323133373831333865653562613533666235326536363831353735616330353862376165
|
||||
36633034356462363462336332363138386334353261386565363438303861333039353130613065
|
||||
34633363656337633666613564613533663632323063613432333061326530383537343632386332
|
||||
38636666666666653562343334323036366635346263333261396435396331613763323034633732
|
||||
38386331666432653231353534376331616462383930353839643765653163316465366135636138
|
||||
33666630386135353961306532363466316335326534323930333237353334623661376337646465
|
||||
62356461366665656632663339656333346233363563326239366430653639343361333933663037
|
||||
63323836626639303933353532316233616462393561623364643932646136666435633661653461
|
||||
64323765393337333339336562343262656237396237363236656265346338633963653537616638
|
||||
36386163373331656661383861633066346666366339313739643439326439663931383463303036
|
||||
35396438323161636534383161346131653561363065386432366136313233373864356665623066
|
||||
65373866646161646566656331646237313339613464396330613834373762333461623462366132
|
||||
38303661643038336439643461363864616165316632663638613338376666656563633535633236
|
||||
34303964626336333134393562643831343031306661316261393838306664613339613361613734
|
||||
38636530366234373539613830376265393630383765303337643037323634303566623838616132
|
||||
38643165356338666465643561326265613933663563353739653333616531636631346438336161
|
||||
31316239393238383063373464653331363061636331336265323862326462373537343665643837
|
||||
32333964343237666532396662323935303933336234623936323433666564303234663063663835
|
||||
30393036303132306530646331383862376532376232323966346331343865643739303465613233
|
||||
30373133393030616565346238393832383430373066633637313064333434373233616432633639
|
||||
37663963376466663337333332373239326131383338326462393464313734326339623430343266
|
||||
30373938636666303165633338656231323633616138303839323863323162313438643562316462
|
||||
36653762653533393437613834666165663335643638376139616162666332323336633031373864
|
||||
38666331343431613163313639353563663663323833663939653034323532333732363033326638
|
||||
37356263346366356162663933616664656664613935346130313534366338316136636336366533
|
||||
39623464323536653737316565613366313936613631366636626534323333343134656364363338
|
||||
33333037623063636538353330643435353066643262633066333466383330376661623839646362
|
||||
37366239623836353161613861396137326564666562383764343665633038373765653234343536
|
||||
34366335626332613562363334326264613231663865393434353430373966623265643466616564
|
||||
64373533303665616538353835663536366162616161313934373364363866343436343231636663
|
||||
61646461353365303265363038353239316161376361616233626533643839396462346236326461
|
||||
30646132316238653561313530356535613937353632343633613733313839323539623264333534
|
||||
30633831623333313634623437356163393766626532353035356465303136373938333163643233
|
||||
38653662343931333234626431356238613432393334663434613332353934303839653966343039
|
||||
37346462616436383934373364353937313331353864663738316438613464353566666466346536
|
||||
37643938636232613039636635653566613264636636366539326566343162646465656465613733
|
||||
66386366353362646435313561663530376264336163333537343433353365313931646462376564
|
||||
62646466616636323933326365313332376364386634393464376466306466656131346531646331
|
||||
66326130316239313136393434616238343938646165613530323563313933636330333536663834
|
||||
61666332323863613231653033396531633236666632353138333334646333306333663130613032
|
||||
30323432346534626665616139393463633065323837353136323135653834303536386161636564
|
||||
35643663333534356639616635323937323061393665373139613665343131353030343366303065
|
||||
39326437313034303334303935633163363132646336653865323564636662356136316638373637
|
||||
35386533383563396132323239376235366634666230313165663039303236316235373136623466
|
||||
66633964363163336665393636656537623963326562323430346661303964626262363066373237
|
||||
34643431663465323231303634326239646536303832313762646335363232303563356630366438
|
||||
37346639366237333166633966623066333330393863373535346361646662373862323264333431
|
||||
63666330356332376435356562326530366631623466666566303433363164613935393132663232
|
||||
33646464393532303862343432653333386139343437306538353330343963303637333935613736
|
||||
37383534346231643937633631633831303035363435356465376637626438656435643438653032
|
||||
3932
|
||||
|
||||
173
backup.sh
Executable file
173
backup.sh
Executable file
@@ -0,0 +1,173 @@
|
||||
#!/bin/bash
|
||||
# E-Ticket - Script d'export pour migration de serveur
|
||||
# Genere un bundle complet et autonome pour migrer l'application sur un autre serveur.
|
||||
#
|
||||
# Le bundle contient:
|
||||
# - dump de la base PostgreSQL (db.sql.gz)
|
||||
# - uploads Vich/Flysystem (events, billets, logos) (public_uploads.tar.gz)
|
||||
# - etat applicatif var/ (var_state.tar.gz)
|
||||
# payouts/, billets/, invoices/, unsubscribed.json
|
||||
# - configuration runtime sensible (env.local, cert/)
|
||||
# - manifest avec checksums SHA-256 (manifest.txt)
|
||||
#
|
||||
# Le tout est ensuite empaquete dans une archive .tar.gz transferable par scp/rsync.
|
||||
#
|
||||
# Usage:
|
||||
# ./backup.sh [DOSSIER_DESTINATION]
|
||||
#
|
||||
# Variables d'environnement supportees:
|
||||
# COMPOSE_FILE : fichier docker-compose a utiliser (defaut: docker-compose-prod.yml)
|
||||
# DB_SERVICE : service Docker de la base (defaut: db-master)
|
||||
# DB_USER : utilisateur PostgreSQL (defaut: e-ticket)
|
||||
# DB_NAME : base de donnees a exporter (defaut: e-ticket)
|
||||
# SKIP_SECRETS : '1' pour exclure .env.local + cert (defaut: inclus)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# --- Configuration ---
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DEST_DIR="${1:-${SCRIPT_DIR}/var/migration}"
|
||||
COMPOSE_FILE="${COMPOSE_FILE:-${SCRIPT_DIR}/docker-compose-prod.yml}"
|
||||
DB_SERVICE="${DB_SERVICE:-db-master}"
|
||||
DB_USER="${DB_USER:-e-ticket}"
|
||||
DB_NAME="${DB_NAME:-e-ticket}"
|
||||
SKIP_SECRETS="${SKIP_SECRETS:-0}"
|
||||
|
||||
DATE="$(date +%Y%m%d_%H%M%S)"
|
||||
BUNDLE_NAME="e_ticket_migration_${DATE}"
|
||||
WORK_DIR="${DEST_DIR}/${BUNDLE_NAME}"
|
||||
BUNDLE_FILE="${DEST_DIR}/${BUNDLE_NAME}.tar.gz"
|
||||
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||
}
|
||||
|
||||
err() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERREUR: $*" >&2
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if [ -d "${WORK_DIR}" ]; then
|
||||
rm -rf "${WORK_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Cleanup du WORK_DIR meme en cas d'erreur (le BUNDLE_FILE final reste)
|
||||
trap cleanup EXIT
|
||||
|
||||
# --- Verifications prealables ---
|
||||
if [ ! -f "${COMPOSE_FILE}" ]; then
|
||||
err "Fichier docker-compose introuvable: ${COMPOSE_FILE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! docker compose -f "${COMPOSE_FILE}" ps --services --status running 2>/dev/null | grep -qx "${DB_SERVICE}"; then
|
||||
err "Le service '${DB_SERVICE}' n'est pas demarre"
|
||||
err "Demarrer la stack avec: make start_prod"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${WORK_DIR}"
|
||||
|
||||
log "=== Export de migration E-Ticket ==="
|
||||
log "Bundle: ${BUNDLE_NAME}"
|
||||
log "Destination: ${DEST_DIR}"
|
||||
|
||||
# --- 1. Dump base de donnees ---
|
||||
log "[1/5] Dump PostgreSQL '${DB_NAME}' depuis ${DB_SERVICE}..."
|
||||
if ! docker compose -f "${COMPOSE_FILE}" exec -T "${DB_SERVICE}" \
|
||||
pg_dump -U "${DB_USER}" -d "${DB_NAME}" \
|
||||
--clean --if-exists --no-owner --no-privileges --quote-all-identifiers \
|
||||
| gzip > "${WORK_DIR}/db.sql.gz"; then
|
||||
err "Echec du dump PostgreSQL"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -s "${WORK_DIR}/db.sql.gz" ]; then
|
||||
err "Le dump PostgreSQL est vide"
|
||||
exit 1
|
||||
fi
|
||||
log " OK ($(du -h "${WORK_DIR}/db.sql.gz" | cut -f1))"
|
||||
|
||||
# --- 2. Uploads publics (events, billets, logos) ---
|
||||
log "[2/5] Archivage public/uploads (events, billets, logos)..."
|
||||
if [ -d "${SCRIPT_DIR}/public/uploads" ]; then
|
||||
tar -czf "${WORK_DIR}/public_uploads.tar.gz" -C "${SCRIPT_DIR}/public" uploads
|
||||
log " OK ($(du -h "${WORK_DIR}/public_uploads.tar.gz" | cut -f1))"
|
||||
else
|
||||
err "public/uploads introuvable"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- 3. Etat applicatif var/ (PDFs generes, desinscrits...) ---
|
||||
log "[3/5] Archivage etat applicatif var/ (payouts, billets, invoices, unsubscribed.json)..."
|
||||
VAR_ITEMS=()
|
||||
for item in payouts billets invoices unsubscribed.json; do
|
||||
if [ -e "${SCRIPT_DIR}/var/${item}" ]; then
|
||||
VAR_ITEMS+=("${item}")
|
||||
fi
|
||||
done
|
||||
if [ ${#VAR_ITEMS[@]} -gt 0 ]; then
|
||||
tar -czf "${WORK_DIR}/var_state.tar.gz" -C "${SCRIPT_DIR}/var" "${VAR_ITEMS[@]}"
|
||||
log " OK - elements inclus: ${VAR_ITEMS[*]} ($(du -h "${WORK_DIR}/var_state.tar.gz" | cut -f1))"
|
||||
else
|
||||
log " Aucun element a archiver dans var/ (saut)"
|
||||
fi
|
||||
|
||||
# --- 4. Configuration runtime sensible ---
|
||||
if [ "${SKIP_SECRETS}" = "1" ]; then
|
||||
log "[4/5] Secrets exclus (SKIP_SECRETS=1)"
|
||||
log " ATTENTION: vous devrez deployer .env.local et config/cert/ manuellement sur le nouveau serveur"
|
||||
else
|
||||
log "[4/5] Archivage configuration sensible (.env.local + config/cert/)..."
|
||||
SECRET_ITEMS=()
|
||||
if [ -f "${SCRIPT_DIR}/.env.local" ]; then
|
||||
cp -p "${SCRIPT_DIR}/.env.local" "${WORK_DIR}/env.local"
|
||||
chmod 600 "${WORK_DIR}/env.local"
|
||||
SECRET_ITEMS+=(".env.local")
|
||||
fi
|
||||
if [ -d "${SCRIPT_DIR}/config/cert" ]; then
|
||||
mkdir -p "${WORK_DIR}/cert"
|
||||
cp -rp "${SCRIPT_DIR}/config/cert/." "${WORK_DIR}/cert/"
|
||||
chmod -R go-rwx "${WORK_DIR}/cert"
|
||||
SECRET_ITEMS+=("config/cert/")
|
||||
fi
|
||||
if [ ${#SECRET_ITEMS[@]} -gt 0 ]; then
|
||||
log " OK - elements inclus: ${SECRET_ITEMS[*]}"
|
||||
else
|
||||
log " Aucun secret trouve a archiver (saut)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 5. Manifest avec checksums et metadata ---
|
||||
log "[5/5] Generation du manifest..."
|
||||
{
|
||||
echo "# E-Ticket migration bundle"
|
||||
echo "bundle_name: ${BUNDLE_NAME}"
|
||||
echo "created_at: $(date --iso-8601=seconds)"
|
||||
echo "source_host: $(hostname)"
|
||||
echo "git_commit: $(git -C "${SCRIPT_DIR}" rev-parse HEAD 2>/dev/null || echo 'unknown')"
|
||||
echo "git_branch: $(git -C "${SCRIPT_DIR}" rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')"
|
||||
echo "db_name: ${DB_NAME}"
|
||||
echo "db_user: ${DB_USER}"
|
||||
echo "skip_secrets: ${SKIP_SECRETS}"
|
||||
echo
|
||||
echo "# SHA-256 checksums"
|
||||
(cd "${WORK_DIR}" && find . -type f ! -name 'manifest.txt' -print0 | sort -z | xargs -0 sha256sum)
|
||||
} > "${WORK_DIR}/manifest.txt"
|
||||
log " OK"
|
||||
|
||||
# --- Empaquetage final ---
|
||||
log "Empaquetage du bundle dans ${BUNDLE_FILE}..."
|
||||
tar -czf "${BUNDLE_FILE}" -C "${DEST_DIR}" "${BUNDLE_NAME}"
|
||||
BUNDLE_SIZE="$(du -h "${BUNDLE_FILE}" | cut -f1)"
|
||||
BUNDLE_SHA="$(sha256sum "${BUNDLE_FILE}" | cut -d' ' -f1)"
|
||||
|
||||
log "=== Export termine ==="
|
||||
log "Bundle : ${BUNDLE_FILE}"
|
||||
log "Taille : ${BUNDLE_SIZE}"
|
||||
log "SHA-256 : ${BUNDLE_SHA}"
|
||||
log
|
||||
log "Pour transferer vers le nouveau serveur:"
|
||||
log " scp '${BUNDLE_FILE}' user@nouveau-serveur:/var/www/e-ticket/"
|
||||
log "Puis sur le nouveau serveur:"
|
||||
log " ./restore.sh '${BUNDLE_NAME}.tar.gz'"
|
||||
@@ -24,7 +24,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
opcache \
|
||||
&& pecl install redis imagick \
|
||||
&& docker-php-ext-enable redis imagick \
|
||||
&& groupadd -g 1000 appuser && useradd -u 1000 -g appuser -m appuser
|
||||
&& groupadd -g 1001 appuser && useradd -u 1001 -g appuser -m appuser
|
||||
|
||||
COPY php.ini /usr/local/etc/php/conf.d/app.ini
|
||||
COPY opcache.ini /usr/local/etc/php/conf.d/opcache.ini
|
||||
|
||||
327
restore.sh
Executable file
327
restore.sh
Executable file
@@ -0,0 +1,327 @@
|
||||
#!/bin/bash
|
||||
# E-Ticket - Script d'import pour migration de serveur
|
||||
# Restaure un bundle de migration genere par backup.sh sur un nouveau serveur.
|
||||
#
|
||||
# Le bundle est attendu au format e_ticket_migration_<DATE>.tar.gz et contient:
|
||||
# db.sql.gz, public_uploads.tar.gz, var_state.tar.gz, env.local, cert/, manifest.txt
|
||||
#
|
||||
# A la fin, le script chown automatiquement les fichiers restaures vers RESTORE_OWNER
|
||||
# (defaut: bot) afin que l'utilisateur PHP du conteneur puisse y ecrire, et purge
|
||||
# var/cache pour eviter les fichiers obsoletes appartenant a un autre utilisateur.
|
||||
#
|
||||
# Usage:
|
||||
# ./restore.sh <bundle.tar.gz> [options]
|
||||
#
|
||||
# Variables d'environnement supportees:
|
||||
# COMPOSE_FILE : fichier docker-compose a utiliser (defaut: docker-compose-prod.yml)
|
||||
# DB_SERVICE : service Docker de la base (defaut: db-master)
|
||||
# DB_USER : utilisateur PostgreSQL (defaut: e-ticket)
|
||||
# DB_NAME : base de donnees a restaurer (defaut: e-ticket)
|
||||
# RESTORE_OWNER : user:group pour le chown final (defaut: bot:bot)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
COMPOSE_FILE="${COMPOSE_FILE:-${SCRIPT_DIR}/docker-compose-prod.yml}"
|
||||
DB_SERVICE="${DB_SERVICE:-db-master}"
|
||||
DB_USER="${DB_USER:-e-ticket}"
|
||||
DB_NAME="${DB_NAME:-e-ticket}"
|
||||
RESTORE_OWNER="${RESTORE_OWNER:-bot:bot}"
|
||||
|
||||
BUNDLE=""
|
||||
ASSUME_YES="false"
|
||||
SKIP_DB="false"
|
||||
SKIP_UPLOADS="false"
|
||||
SKIP_VAR="false"
|
||||
SKIP_SECRETS="false"
|
||||
SKIP_CHOWN="false"
|
||||
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||
}
|
||||
|
||||
err() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERREUR: $*" >&2
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
sudo ./restore.sh <bundle.tar.gz> [options]
|
||||
|
||||
Options:
|
||||
--yes, -y Mode non interactif (pas de confirmation)
|
||||
--skip-db Ne pas restaurer la base de donnees
|
||||
--skip-uploads Ne pas restaurer public/uploads
|
||||
--skip-var Ne pas restaurer var/ (payouts, billets, invoices, unsubscribed.json)
|
||||
--skip-secrets Ne pas restaurer .env.local et config/cert/
|
||||
--skip-chown Ne pas faire le chown final (deconseille)
|
||||
--owner USER:GRP Utilisateur:groupe pour le chown final (defaut: bot:bot)
|
||||
-h, --help Affiche cette aide
|
||||
|
||||
Variables d'environnement (alternatives aux flags):
|
||||
RESTORE_OWNER Equivalent de --owner
|
||||
|
||||
ATTENTION: La restauration ECRASE les donnees existantes !
|
||||
ATTENTION: Le chown final necessite root (sudo).
|
||||
EOF
|
||||
}
|
||||
|
||||
# --- Parsing des arguments ---
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--yes|-y) ASSUME_YES="true"; shift ;;
|
||||
--skip-db) SKIP_DB="true"; shift ;;
|
||||
--skip-uploads) SKIP_UPLOADS="true"; shift ;;
|
||||
--skip-var) SKIP_VAR="true"; shift ;;
|
||||
--skip-secrets) SKIP_SECRETS="true"; shift ;;
|
||||
--skip-chown) SKIP_CHOWN="true"; shift ;;
|
||||
--owner)
|
||||
if [ $# -lt 2 ]; then
|
||||
err "--owner requiert une valeur (ex: --owner bot:bot)"
|
||||
exit 1
|
||||
fi
|
||||
RESTORE_OWNER="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
--*) err "Option inconnue: $1"; usage; exit 1 ;;
|
||||
*)
|
||||
if [ -z "${BUNDLE}" ]; then
|
||||
BUNDLE="$1"
|
||||
else
|
||||
err "Argument en trop: $1"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# --- Verification root pour le chown final ---
|
||||
if [ "${SKIP_CHOWN}" = "false" ] && [ "$(id -u)" != "0" ]; then
|
||||
err "Ce script doit etre execute en root (sudo) pour le chown final vers ${RESTORE_OWNER}"
|
||||
err "Soit relancer avec sudo, soit ajouter --skip-chown (deconseille)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Verification que le user/group cible existe ---
|
||||
if [ "${SKIP_CHOWN}" = "false" ]; then
|
||||
OWNER_USER="${RESTORE_OWNER%%:*}"
|
||||
OWNER_GROUP="${RESTORE_OWNER##*:}"
|
||||
if ! id -u "${OWNER_USER}" >/dev/null 2>&1; then
|
||||
err "Utilisateur '${OWNER_USER}' introuvable sur le systeme"
|
||||
exit 1
|
||||
fi
|
||||
if ! getent group "${OWNER_GROUP}" >/dev/null 2>&1; then
|
||||
err "Groupe '${OWNER_GROUP}' introuvable sur le systeme"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "${BUNDLE}" ]; then
|
||||
err "Aucun bundle specifie"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${BUNDLE}" ]; then
|
||||
err "Bundle introuvable: ${BUNDLE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Extraction du bundle dans un dossier temporaire ---
|
||||
TMP_DIR="$(mktemp -d -t e_ticket_restore_XXXXXX)"
|
||||
cleanup() {
|
||||
rm -rf "${TMP_DIR}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
log "=== Restauration du bundle de migration E-Ticket ==="
|
||||
log "Bundle: ${BUNDLE}"
|
||||
log "Extraction dans ${TMP_DIR}..."
|
||||
|
||||
if ! tar -xzf "${BUNDLE}" -C "${TMP_DIR}"; then
|
||||
err "Echec d'extraction du bundle"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Trouve le dossier extrait (e_ticket_migration_<DATE>)
|
||||
EXTRACTED_DIR="$(find "${TMP_DIR}" -maxdepth 1 -mindepth 1 -type d -name 'e_ticket_migration_*' | head -n1)"
|
||||
if [ -z "${EXTRACTED_DIR}" ] || [ ! -d "${EXTRACTED_DIR}" ]; then
|
||||
err "Bundle invalide: dossier e_ticket_migration_* introuvable"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Verification du manifest et des checksums ---
|
||||
if [ ! -f "${EXTRACTED_DIR}/manifest.txt" ]; then
|
||||
err "Manifest manquant dans le bundle"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Verification des checksums..."
|
||||
(cd "${EXTRACTED_DIR}" && grep -E '^[a-f0-9]{64} ' manifest.txt | sha256sum -c --quiet) || {
|
||||
err "Checksums invalides - bundle corrompu"
|
||||
exit 1
|
||||
}
|
||||
log " OK - bundle integre"
|
||||
|
||||
echo
|
||||
echo "================================================================"
|
||||
echo " Manifest du bundle:"
|
||||
echo "================================================================"
|
||||
grep -E '^(bundle_name|created_at|source_host|git_commit|git_branch|db_name|skip_secrets):' "${EXTRACTED_DIR}/manifest.txt" || true
|
||||
echo "================================================================"
|
||||
|
||||
# --- Verification des composants disponibles ---
|
||||
HAS_DB="false"
|
||||
HAS_UPLOADS="false"
|
||||
HAS_VAR="false"
|
||||
HAS_ENV="false"
|
||||
HAS_CERT="false"
|
||||
[ -f "${EXTRACTED_DIR}/db.sql.gz" ] && HAS_DB="true"
|
||||
[ -f "${EXTRACTED_DIR}/public_uploads.tar.gz" ] && HAS_UPLOADS="true"
|
||||
[ -f "${EXTRACTED_DIR}/var_state.tar.gz" ] && HAS_VAR="true"
|
||||
[ -f "${EXTRACTED_DIR}/env.local" ] && HAS_ENV="true"
|
||||
[ -d "${EXTRACTED_DIR}/cert" ] && HAS_CERT="true"
|
||||
|
||||
echo
|
||||
echo " Plan de restauration:"
|
||||
echo "----------------------------------------------------------------"
|
||||
[ "${HAS_DB}" = "true" ] && [ "${SKIP_DB}" = "false" ] && echo " [X] Base de donnees -> ${DB_NAME} (ECRASE)" || echo " [ ] Base de donnees"
|
||||
[ "${HAS_UPLOADS}" = "true" ] && [ "${SKIP_UPLOADS}" = "false" ] && echo " [X] public/uploads/ (ECRASE, sauvegarde de securite)" || echo " [ ] public/uploads/"
|
||||
[ "${HAS_VAR}" = "true" ] && [ "${SKIP_VAR}" = "false" ] && echo " [X] var/ (payouts, billets, invoices, unsubscribed.json)" || echo " [ ] var/"
|
||||
[ "${HAS_ENV}" = "true" ] && [ "${SKIP_SECRETS}" = "false" ] && echo " [X] .env.local (ECRASE)" || echo " [ ] .env.local"
|
||||
[ "${HAS_CERT}" = "true" ] && [ "${SKIP_SECRETS}" = "false" ] && echo " [X] config/cert/ (ECRASE)" || echo " [ ] config/cert/"
|
||||
echo "----------------------------------------------------------------"
|
||||
echo
|
||||
|
||||
if [ "${ASSUME_YES}" != "true" ]; then
|
||||
read -r -p "Confirmer la restauration ? (tapez 'oui' pour continuer) : " CONFIRM
|
||||
if [ "${CONFIRM}" != "oui" ]; then
|
||||
log "Restauration annulee par l'utilisateur"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 1. Secrets (en premier pour que la stack puisse demarrer si besoin) ---
|
||||
if [ "${SKIP_SECRETS}" = "false" ]; then
|
||||
if [ "${HAS_ENV}" = "true" ]; then
|
||||
log "[secrets] Restauration de .env.local..."
|
||||
if [ -f "${SCRIPT_DIR}/.env.local" ]; then
|
||||
cp -p "${SCRIPT_DIR}/.env.local" "${SCRIPT_DIR}/.env.local.before_restore_$(date +%Y%m%d_%H%M%S)"
|
||||
fi
|
||||
cp -p "${EXTRACTED_DIR}/env.local" "${SCRIPT_DIR}/.env.local"
|
||||
chmod 600 "${SCRIPT_DIR}/.env.local"
|
||||
log " OK"
|
||||
fi
|
||||
if [ "${HAS_CERT}" = "true" ]; then
|
||||
log "[secrets] Restauration de config/cert/..."
|
||||
mkdir -p "${SCRIPT_DIR}/config/cert"
|
||||
cp -rp "${EXTRACTED_DIR}/cert/." "${SCRIPT_DIR}/config/cert/"
|
||||
chmod -R go-rwx "${SCRIPT_DIR}/config/cert"
|
||||
log " OK"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 2. Base de donnees ---
|
||||
if [ "${HAS_DB}" = "true" ] && [ "${SKIP_DB}" = "false" ]; then
|
||||
log "[db] Verification du service ${DB_SERVICE}..."
|
||||
if [ ! -f "${COMPOSE_FILE}" ]; then
|
||||
err "Fichier docker-compose introuvable: ${COMPOSE_FILE}"
|
||||
exit 1
|
||||
fi
|
||||
if ! docker compose -f "${COMPOSE_FILE}" ps --services --status running 2>/dev/null | grep -qx "${DB_SERVICE}"; then
|
||||
err "Le service '${DB_SERVICE}' n'est pas demarre. Lancer: make start_prod"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "[db] Restauration de la base ${DB_NAME}..."
|
||||
if ! gunzip -c "${EXTRACTED_DIR}/db.sql.gz" \
|
||||
| docker compose -f "${COMPOSE_FILE}" exec -T "${DB_SERVICE}" \
|
||||
psql -U "${DB_USER}" -d "${DB_NAME}" -v ON_ERROR_STOP=1 >/dev/null; then
|
||||
err "Echec de la restauration PostgreSQL"
|
||||
exit 1
|
||||
fi
|
||||
log " OK"
|
||||
fi
|
||||
|
||||
# --- 3. public/uploads ---
|
||||
if [ "${HAS_UPLOADS}" = "true" ] && [ "${SKIP_UPLOADS}" = "false" ]; then
|
||||
log "[uploads] Restauration de public/uploads..."
|
||||
if [ -d "${SCRIPT_DIR}/public/uploads" ]; then
|
||||
SAFETY="${SCRIPT_DIR}/public/uploads.before_restore_$(date +%Y%m%d_%H%M%S)"
|
||||
log " Sauvegarde de securite: ${SAFETY}"
|
||||
mv "${SCRIPT_DIR}/public/uploads" "${SAFETY}"
|
||||
fi
|
||||
mkdir -p "${SCRIPT_DIR}/public"
|
||||
if ! tar -xzf "${EXTRACTED_DIR}/public_uploads.tar.gz" -C "${SCRIPT_DIR}/public"; then
|
||||
err "Echec d'extraction de public_uploads.tar.gz"
|
||||
exit 1
|
||||
fi
|
||||
log " OK"
|
||||
fi
|
||||
|
||||
# --- 4. var/ (PDFs generes, unsubscribed.json...) ---
|
||||
if [ "${HAS_VAR}" = "true" ] && [ "${SKIP_VAR}" = "false" ]; then
|
||||
log "[var] Restauration de var/ (payouts, billets, invoices, unsubscribed.json)..."
|
||||
mkdir -p "${SCRIPT_DIR}/var"
|
||||
# Sauvegarde de securite des elements existants qui seront ecrases
|
||||
SAFETY_VAR="${SCRIPT_DIR}/var/.before_restore_$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "${SAFETY_VAR}"
|
||||
for item in payouts billets invoices unsubscribed.json; do
|
||||
if [ -e "${SCRIPT_DIR}/var/${item}" ]; then
|
||||
mv "${SCRIPT_DIR}/var/${item}" "${SAFETY_VAR}/"
|
||||
fi
|
||||
done
|
||||
# Si rien n'a ete sauvegarde, on supprime le dossier vide
|
||||
if [ -z "$(ls -A "${SAFETY_VAR}")" ]; then
|
||||
rmdir "${SAFETY_VAR}"
|
||||
else
|
||||
log " Sauvegarde de securite: ${SAFETY_VAR}"
|
||||
fi
|
||||
if ! tar -xzf "${EXTRACTED_DIR}/var_state.tar.gz" -C "${SCRIPT_DIR}/var"; then
|
||||
err "Echec d'extraction de var_state.tar.gz"
|
||||
exit 1
|
||||
fi
|
||||
log " OK"
|
||||
fi
|
||||
|
||||
# --- 5. Purge du cache Symfony ---
|
||||
# Indispensable: var/cache contient des fichiers compiles avec les anciens
|
||||
# uid/gid et peut empecher PHP d'ecrire au demarrage suivant.
|
||||
if [ -d "${SCRIPT_DIR}/var/cache" ]; then
|
||||
log "[cache] Purge de var/cache (sera reconstruit par PHP au demarrage)..."
|
||||
rm -rf "${SCRIPT_DIR}/var/cache"
|
||||
log " OK"
|
||||
fi
|
||||
|
||||
# --- 6. Chown final pour matcher l'utilisateur PHP du conteneur ---
|
||||
if [ "${SKIP_CHOWN}" = "false" ]; then
|
||||
log "[chown] Application de '${RESTORE_OWNER}' sur les fichiers restaures..."
|
||||
CHOWN_TARGETS=()
|
||||
[ -d "${SCRIPT_DIR}/var" ] && CHOWN_TARGETS+=("${SCRIPT_DIR}/var")
|
||||
[ -d "${SCRIPT_DIR}/public/uploads" ] && CHOWN_TARGETS+=("${SCRIPT_DIR}/public/uploads")
|
||||
[ -d "${SCRIPT_DIR}/config/cert" ] && CHOWN_TARGETS+=("${SCRIPT_DIR}/config/cert")
|
||||
[ -f "${SCRIPT_DIR}/.env.local" ] && CHOWN_TARGETS+=("${SCRIPT_DIR}/.env.local")
|
||||
|
||||
if [ ${#CHOWN_TARGETS[@]} -gt 0 ]; then
|
||||
chown -R "${RESTORE_OWNER}" "${CHOWN_TARGETS[@]}"
|
||||
log " OK - cibles: ${CHOWN_TARGETS[*]}"
|
||||
else
|
||||
log " Aucune cible a chown"
|
||||
fi
|
||||
else
|
||||
log "[chown] Saut du chown final (--skip-chown)"
|
||||
log " ATTENTION: PHP pourrait ne pas avoir les droits d'ecriture sur var/, public/uploads/..."
|
||||
fi
|
||||
|
||||
log "=== Migration terminee avec succes ==="
|
||||
log
|
||||
log "Etapes recommandees post-migration:"
|
||||
log " 1. make build_prod (si l'image PHP n'a pas ete reconstruite avec le bon UID)"
|
||||
log " 2. make start_prod (si pas deja fait)"
|
||||
log " 3. make migrate_prod (appliquer les migrations Doctrine eventuelles)"
|
||||
log " 4. make clear_prod (vider le cache)"
|
||||
log " 5. Verifier le bon fonctionnement de l'application"
|
||||
@@ -11,8 +11,6 @@ sonar.test.inclusions=tests/**/*.php,tests/js/**/*.test.js
|
||||
sonar.javascript.lcov.reportPaths=coverage/lcov.info
|
||||
sonar.eslint.reportPaths=eslint-report.json
|
||||
sonar.docker.hadolint.reportPaths=hadolint-dev.json,hadolint-prod.json
|
||||
sonar.dependencyCheck.jsonReportPath=dependency-check-report.json
|
||||
sonar.dependencyCheck.htmlReportPath=dependency-check-report.html
|
||||
sonar.cpd.exclusions=templates/pdf/**
|
||||
sonar.issue.ignore.multicriteria=e1
|
||||
sonar.issue.ignore.multicriteria.e1.ruleKey=css:S4662
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\BilletBuyer;
|
||||
use App\Entity\User;
|
||||
use App\Service\AuditService;
|
||||
use App\Service\BilletOrderService;
|
||||
use App\Service\MailerService;
|
||||
use App\Service\StripeService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
@@ -17,16 +13,13 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'app:stripe:sync',
|
||||
description: 'Sync Stripe account status for all organizers and reconcile pending orders',
|
||||
description: 'Sync Stripe account status for all organizers',
|
||||
)]
|
||||
class StripeSyncCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private StripeService $stripeService,
|
||||
private BilletOrderService $billetOrderService,
|
||||
private MailerService $mailerService,
|
||||
private AuditService $audit,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
@@ -36,7 +29,6 @@ class StripeSyncCommand extends Command
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$hasErrors = $this->syncAccounts($io);
|
||||
$hasErrors = $this->syncPendingOrders($io) || $hasErrors;
|
||||
|
||||
return $hasErrors ? Command::FAILURE : Command::SUCCESS;
|
||||
}
|
||||
@@ -100,116 +92,4 @@ class StripeSyncCommand extends Command
|
||||
|
||||
return $errors > 0;
|
||||
}
|
||||
|
||||
private function syncPendingOrders(SymfonyStyle $io): bool
|
||||
{
|
||||
$pendingOrders = $this->em->getRepository(BilletBuyer::class)->findBy([
|
||||
'status' => BilletBuyer::STATUS_PENDING,
|
||||
]);
|
||||
|
||||
if (0 === \count($pendingOrders)) {
|
||||
$io->info('No pending orders to reconcile.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$io->info(sprintf('Checking %d pending order(s) on Stripe...', \count($pendingOrders)));
|
||||
|
||||
$processed = 0;
|
||||
$errors = 0;
|
||||
|
||||
foreach ($pendingOrders as $order) {
|
||||
$paymentIntentId = $order->getStripeSessionId();
|
||||
|
||||
$stripeAccountId = $order->getEvent()?->getAccount()?->getStripeAccountId();
|
||||
|
||||
if (!$paymentIntentId || !$stripeAccountId) {
|
||||
$io->text(sprintf(' [<fg=yellow>SKIP</>] Order #%s — no payment intent ID or Stripe account', $order->getOrderNumber()));
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$paymentIntent = $this->stripeService->retrievePaymentIntent($paymentIntentId, $stripeAccountId);
|
||||
$stripeStatus = $paymentIntent->status;
|
||||
|
||||
match ($stripeStatus) {
|
||||
'succeeded' => $this->handleSucceeded($order, $paymentIntent, $io),
|
||||
'canceled' => $this->handleCancelled($order, $io),
|
||||
'requires_payment_method' => $this->handleFailed($order, $paymentIntent, $io),
|
||||
default => $io->text(sprintf(
|
||||
' [<fg=blue>PENDING</>] Order #%s — Stripe status: %s',
|
||||
$order->getOrderNumber(),
|
||||
$stripeStatus,
|
||||
)),
|
||||
};
|
||||
|
||||
++$processed;
|
||||
} catch (\Throwable $e) {
|
||||
$io->text(sprintf(
|
||||
' [<fg=red>ERROR</>] Order #%s — %s',
|
||||
$order->getOrderNumber(),
|
||||
$e->getMessage(),
|
||||
));
|
||||
++$errors;
|
||||
}
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
|
||||
$io->success(sprintf('Orders: %d checked, %d error(s).', $processed, $errors));
|
||||
|
||||
return $errors > 0;
|
||||
}
|
||||
|
||||
private function handleSucceeded(BilletBuyer $order, \Stripe\PaymentIntent $paymentIntent, SymfonyStyle $io): void
|
||||
{
|
||||
$debtOrganizerId = $paymentIntent->metadata->debt_organizer_id ?? null;
|
||||
if ($debtOrganizerId) {
|
||||
$organizer = $this->em->getRepository(User::class)->find((int) $debtOrganizerId);
|
||||
if ($organizer) {
|
||||
$organizer->reduceDebt($paymentIntent->amount ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
$this->billetOrderService->generateOrderTickets($order);
|
||||
$this->billetOrderService->generateAndSendTickets($order);
|
||||
$this->billetOrderService->notifyOrganizer($order);
|
||||
|
||||
$io->text(sprintf(' [<fg=green>PAID</>] Order #%s — tickets generated and sent', $order->getOrderNumber()));
|
||||
}
|
||||
|
||||
private function handleCancelled(BilletBuyer $order, SymfonyStyle $io): void
|
||||
{
|
||||
$order->setStatus(BilletBuyer::STATUS_CANCELLED);
|
||||
$this->em->flush();
|
||||
|
||||
$this->audit->log('payment_cancelled_sync', 'BilletBuyer', $order->getId(), [
|
||||
'orderNumber' => $order->getOrderNumber(),
|
||||
]);
|
||||
|
||||
$io->text(sprintf(' [<fg=red>CANCELLED</>] Order #%s', $order->getOrderNumber()));
|
||||
}
|
||||
|
||||
private function handleFailed(BilletBuyer $order, \Stripe\PaymentIntent $paymentIntent, SymfonyStyle $io): void
|
||||
{
|
||||
$errorMessage = $paymentIntent->last_payment_error->message ?? 'Paiement refuse';
|
||||
|
||||
$order->setStatus(BilletBuyer::STATUS_CANCELLED);
|
||||
$this->em->flush();
|
||||
|
||||
$this->audit->log('payment_failed_sync', 'BilletBuyer', $order->getId(), [
|
||||
'orderNumber' => $order->getOrderNumber(),
|
||||
'error' => $errorMessage,
|
||||
]);
|
||||
|
||||
if ($order->getEmail()) {
|
||||
$this->mailerService->sendEmail(
|
||||
$order->getEmail(),
|
||||
'Echec de paiement - '.$order->getEvent()->getTitle(),
|
||||
'Votre paiement pour la commande '.$order->getOrderNumber().' a echoue : '.$errorMessage,
|
||||
);
|
||||
}
|
||||
|
||||
$io->text(sprintf(' [<fg=red>FAILED</>] Order #%s — %s', $order->getOrderNumber(), $errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,8 @@ use App\Entity\Payout;
|
||||
use App\Entity\User;
|
||||
use App\Service\AuditService;
|
||||
use App\Service\EventIndexService;
|
||||
use App\Service\ExportService;
|
||||
use App\Service\MailerService;
|
||||
use App\Service\OrderIndexService;
|
||||
use App\Service\PayoutPdfService;
|
||||
use App\Service\StripeService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
@@ -37,8 +35,6 @@ class AccountController extends AbstractController
|
||||
private const EVENT_BASE_URL = '/mon-compte/evenement/';
|
||||
private const DQL_EXCLUDE_INVITATIONS = 'o.isInvitation = false OR o.isInvitation IS NULL';
|
||||
private const DQL_BB_EXCLUDE_INVITATIONS = 'bb.isInvitation = false OR bb.isInvitation IS NULL';
|
||||
private const CONTENT_TYPE_PDF = 'application/pdf';
|
||||
private const PDF_SUFFIX = '.pdf"';
|
||||
|
||||
#[Route('/mon-compte', name: 'app_account')]
|
||||
public function index(Request $request, StripeService $stripeService, EntityManagerInterface $em, PaginatorInterface $paginator, EventIndexService $eventIndex): Response
|
||||
@@ -595,73 +591,6 @@ class AccountController extends AbstractController
|
||||
}
|
||||
}
|
||||
|
||||
/** @codeCoverageIgnore Generates PDF with dompdf */
|
||||
#[Route('/mon-compte/payout/{id}/attestation', name: 'app_account_payout_pdf')]
|
||||
public function payoutPdf(Payout $payout, PayoutPdfService $pdfService): Response
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
|
||||
if ($payout->getOrganizer()->getId() !== $user->getId()) {
|
||||
throw $this->createAccessDeniedException();
|
||||
}
|
||||
|
||||
return new Response($pdfService->generate($payout), 200, [
|
||||
'Content-Type' => self::CONTENT_TYPE_PDF,
|
||||
'Content-Disposition' => 'inline; filename="attestation_'.$payout->getStripePayoutId().self::PDF_SUFFIX,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/mon-compte/export/{year}/{month}', name: 'app_account_export', requirements: ['year' => '\d{4}', 'month' => '\d{1,2}'], methods: ['GET'])]
|
||||
public function export(int $year, int $month, ExportService $exportService): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('ROLE_ORGANIZER');
|
||||
if ($redirect = $this->requireStripeReady()) { // @codeCoverageIgnoreStart
|
||||
return $redirect;
|
||||
} // @codeCoverageIgnoreEnd
|
||||
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
$stats = $exportService->getMonthlyStats($year, $month, $user);
|
||||
$csv = $exportService->generateCsv($stats['orders']);
|
||||
|
||||
$filename = sprintf('export_%04d_%02d.csv', $year, $month);
|
||||
|
||||
return new Response($csv, 200, [
|
||||
'Content-Type' => 'text/csv; charset=utf-8',
|
||||
'Content-Disposition' => 'attachment; filename="'.$filename.'"',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/mon-compte/export/{year}/{month}/pdf', name: 'app_account_export_pdf', requirements: ['year' => '\d{4}', 'month' => '\d{1,2}'], methods: ['GET'])]
|
||||
public function exportPdf(int $year, int $month, ExportService $exportService): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('ROLE_ORGANIZER');
|
||||
if ($redirect = $this->requireStripeReady()) { // @codeCoverageIgnoreStart
|
||||
return $redirect;
|
||||
} // @codeCoverageIgnoreEnd
|
||||
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
$stats = $exportService->getMonthlyStats($year, $month, $user);
|
||||
$pdf = $exportService->generatePdf($stats, $year, $month, $user);
|
||||
|
||||
$filename = sprintf('recap_%04d_%02d.pdf', $year, $month);
|
||||
|
||||
return new Response($pdf, 200, [
|
||||
'Content-Type' => self::CONTENT_TYPE_PDF,
|
||||
'Content-Disposition' => 'inline; filename="'.$filename.'"',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getAllowedBilletTypes(?string $offer): array
|
||||
{
|
||||
return AccountEventCatalogController::getAllowedBilletTypes($offer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<BilletBuyer> $paidOrders
|
||||
*
|
||||
|
||||
@@ -10,8 +10,12 @@ use App\Entity\BilletBuyerItem;
|
||||
use App\Entity\BilletOrder;
|
||||
use App\Entity\Category;
|
||||
use App\Entity\Event;
|
||||
use App\Entity\Payout;
|
||||
use App\Entity\User;
|
||||
use App\Service\AuditService;
|
||||
use App\Service\BilletOrderService;
|
||||
use App\Service\ExportService;
|
||||
use App\Service\PayoutPdfService;
|
||||
use App\Service\StripeService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
@@ -549,4 +553,63 @@ class AccountEventOperationsController extends AbstractController
|
||||
|
||||
return $details;
|
||||
}
|
||||
|
||||
/** @codeCoverageIgnore Generates PDF with dompdf */
|
||||
#[Route('/mon-compte/payout/{id}/attestation', name: 'app_account_payout_pdf')]
|
||||
public function payoutPdf(Payout $payout, PayoutPdfService $pdfService): Response
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
|
||||
if ($payout->getOrganizer()->getId() !== $user->getId()) {
|
||||
throw $this->createAccessDeniedException();
|
||||
}
|
||||
|
||||
return new Response($pdfService->generate($payout), 200, [
|
||||
'Content-Type' => self::CONTENT_TYPE_PDF,
|
||||
'Content-Disposition' => 'inline; filename="attestation_'.$payout->getStripePayoutId().self::PDF_SUFFIX,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/mon-compte/export/{year}/{month}', name: 'app_account_export', requirements: ['year' => '\d{4}', 'month' => '\d{1,2}'], methods: ['GET'])]
|
||||
public function export(int $year, int $month, ExportService $exportService): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('ROLE_ORGANIZER');
|
||||
if ($redirect = $this->requireStripeReady()) { // @codeCoverageIgnoreStart
|
||||
return $redirect;
|
||||
} // @codeCoverageIgnoreEnd
|
||||
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
$stats = $exportService->getMonthlyStats($year, $month, $user);
|
||||
$csv = $exportService->generateCsv($stats['orders']);
|
||||
|
||||
$filename = sprintf('export_%04d_%02d.csv', $year, $month);
|
||||
|
||||
return new Response($csv, 200, [
|
||||
'Content-Type' => 'text/csv; charset=utf-8',
|
||||
'Content-Disposition' => 'attachment; filename="'.$filename.'"',
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/mon-compte/export/{year}/{month}/pdf', name: 'app_account_export_pdf', requirements: ['year' => '\d{4}', 'month' => '\d{1,2}'], methods: ['GET'])]
|
||||
public function exportPdf(int $year, int $month, ExportService $exportService): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('ROLE_ORGANIZER');
|
||||
if ($redirect = $this->requireStripeReady()) { // @codeCoverageIgnoreStart
|
||||
return $redirect;
|
||||
} // @codeCoverageIgnoreEnd
|
||||
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
$stats = $exportService->getMonthlyStats($year, $month, $user);
|
||||
$pdf = $exportService->generatePdf($stats, $year, $month, $user);
|
||||
|
||||
$filename = sprintf('recap_%04d_%02d.pdf', $year, $month);
|
||||
|
||||
return new Response($pdf, 200, [
|
||||
'Content-Type' => self::CONTENT_TYPE_PDF,
|
||||
'Content-Disposition' => 'inline; filename="'.$filename.'"',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
class AdminOrdersController extends AbstractController
|
||||
{
|
||||
private const DQL_STATUS_PAID = 'o.status = :paid';
|
||||
private const DQL_EXCLUDE_INVITATIONS = 'o.isInvitation = false OR o.isInvitation IS NULL';
|
||||
|
||||
#[Route('/commandes', name: 'app_admin_orders', methods: ['GET'])]
|
||||
public function orders(Request $request, EntityManagerInterface $em, PaginatorInterface $paginator): Response
|
||||
|
||||
@@ -12,6 +12,7 @@ use App\Service\BilletOrderService;
|
||||
use App\Service\MailerService;
|
||||
use App\Service\PayoutPdfService;
|
||||
use App\Service\StripeService;
|
||||
use Doctrine\DBAL\LockMode;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
@@ -157,6 +158,23 @@ class StripeWebhookController extends AbstractController
|
||||
return;
|
||||
}
|
||||
|
||||
$canProcess = $em->wrapInTransaction(function () use ($order, $em): bool {
|
||||
$em->refresh($order, LockMode::PESSIMISTIC_WRITE);
|
||||
|
||||
if (BilletBuyer::STATUS_PENDING !== $order->getStatus()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$order->setStatus(BilletBuyer::STATUS_PAID);
|
||||
$order->setPaidAt(new \DateTimeImmutable());
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!$canProcess) {
|
||||
return;
|
||||
}
|
||||
|
||||
$debtOrganizerId = $paymentIntent->metadata->debt_organizer_id ?? null;
|
||||
if ($debtOrganizerId) {
|
||||
$organizer = $em->getRepository(User::class)->find((int) $debtOrganizerId);
|
||||
|
||||
@@ -3,12 +3,7 @@
|
||||
namespace App\Tests\Command;
|
||||
|
||||
use App\Command\StripeSyncCommand;
|
||||
use App\Entity\BilletBuyer;
|
||||
use App\Entity\Event;
|
||||
use App\Entity\User;
|
||||
use App\Service\AuditService;
|
||||
use App\Service\BilletOrderService;
|
||||
use App\Service\MailerService;
|
||||
use App\Service\StripeService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
@@ -19,29 +14,19 @@ use Symfony\Component\Console\Tester\CommandTester;
|
||||
class StripeSyncCommandTest extends TestCase
|
||||
{
|
||||
private StripeService $stripeService;
|
||||
private BilletOrderService $billetOrderService;
|
||||
private MailerService $mailerService;
|
||||
private AuditService $audit;
|
||||
private EntityManagerInterface $em;
|
||||
private EntityRepository $userRepo;
|
||||
private EntityRepository $buyerRepo;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->stripeService = $this->createMock(StripeService::class);
|
||||
$this->billetOrderService = $this->createMock(BilletOrderService::class);
|
||||
$this->mailerService = $this->createMock(MailerService::class);
|
||||
$this->audit = $this->createMock(AuditService::class);
|
||||
|
||||
$this->userRepo = $this->createMock(EntityRepository::class);
|
||||
$this->buyerRepo = $this->createMock(EntityRepository::class);
|
||||
$this->buyerRepo->method('findBy')->willReturn([]);
|
||||
|
||||
$this->em = $this->createMock(EntityManagerInterface::class);
|
||||
$this->em->method('getRepository')->willReturnCallback(function (string $class) {
|
||||
return match ($class) {
|
||||
User::class => $this->userRepo,
|
||||
BilletBuyer::class => $this->buyerRepo,
|
||||
default => $this->createMock(EntityRepository::class),
|
||||
};
|
||||
});
|
||||
@@ -63,29 +48,11 @@ class StripeSyncCommandTest extends TestCase
|
||||
return $user;
|
||||
}
|
||||
|
||||
private function createPendingOrder(?string $paymentIntentId = null): BilletBuyer
|
||||
{
|
||||
$event = $this->createMock(Event::class);
|
||||
$event->method('getTitle')->willReturn('Test Event');
|
||||
$event->method('getAccount')->willReturn($this->createOrganizer('acct_org'));
|
||||
|
||||
$order = new BilletBuyer();
|
||||
$order->setStatus(BilletBuyer::STATUS_PENDING);
|
||||
$order->setStripeSessionId($paymentIntentId);
|
||||
$order->setEmail('buyer@test.fr');
|
||||
$order->setEvent($event);
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
private function createCommandTester(): CommandTester
|
||||
{
|
||||
$command = new StripeSyncCommand(
|
||||
$this->em,
|
||||
$this->stripeService,
|
||||
$this->billetOrderService,
|
||||
$this->mailerService,
|
||||
$this->audit,
|
||||
);
|
||||
|
||||
$app = new Application();
|
||||
@@ -94,23 +61,6 @@ class StripeSyncCommandTest extends TestCase
|
||||
return new CommandTester($app->find('app:stripe:sync'));
|
||||
}
|
||||
|
||||
private function setBuyerRepo(array $orders): void
|
||||
{
|
||||
$this->buyerRepo = $this->createMock(EntityRepository::class);
|
||||
$this->buyerRepo->method('findBy')->willReturn($orders);
|
||||
|
||||
$this->em = $this->createMock(EntityManagerInterface::class);
|
||||
$this->em->method('getRepository')->willReturnCallback(function (string $class) {
|
||||
return match ($class) {
|
||||
User::class => $this->userRepo,
|
||||
BilletBuyer::class => $this->buyerRepo,
|
||||
default => $this->createMock(EntityRepository::class),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// --- Account sync tests ---
|
||||
|
||||
public function testSyncUpdatesStripeStatus(): void
|
||||
{
|
||||
$user = $this->createOrganizer('acct_123');
|
||||
@@ -195,206 +145,4 @@ class StripeSyncCommandTest extends TestCase
|
||||
self::assertTrue($userWithStripe->isStripeChargesEnabled());
|
||||
self::assertFalse($userWithStripe->isStripePayoutsEnabled());
|
||||
}
|
||||
|
||||
// --- Pending orders sync tests ---
|
||||
|
||||
public function testNoPendingOrders(): void
|
||||
{
|
||||
$this->userRepo->method('findAll')->willReturn([]);
|
||||
|
||||
$tester = $this->createCommandTester();
|
||||
$tester->execute([]);
|
||||
|
||||
self::assertStringContainsString('No pending orders', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testPendingOrderSucceeded(): void
|
||||
{
|
||||
$this->userRepo->method('findAll')->willReturn([]);
|
||||
|
||||
$order = $this->createPendingOrder('pi_succeeded');
|
||||
$this->setBuyerRepo([$order]);
|
||||
|
||||
$paymentIntent = \Stripe\PaymentIntent::constructFrom([
|
||||
'id' => 'pi_succeeded',
|
||||
'status' => 'succeeded',
|
||||
'amount' => 5000,
|
||||
'metadata' => [],
|
||||
]);
|
||||
|
||||
$this->stripeService->method('retrievePaymentIntent')
|
||||
->with('pi_succeeded')
|
||||
->willReturn($paymentIntent);
|
||||
|
||||
$this->billetOrderService->expects(self::once())->method('generateOrderTickets')->with($order);
|
||||
$this->billetOrderService->expects(self::once())->method('generateAndSendTickets')->with($order);
|
||||
$this->billetOrderService->expects(self::once())->method('notifyOrganizer')->with($order);
|
||||
|
||||
$tester = $this->createCommandTester();
|
||||
$tester->execute([]);
|
||||
|
||||
self::assertStringContainsString('PAID', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testPendingOrderSucceededWithDebtOrganizer(): void
|
||||
{
|
||||
$organizer = $this->createOrganizer('acct_debt');
|
||||
$this->userRepo->method('findAll')->willReturn([]);
|
||||
$this->userRepo->method('find')->with(42)->willReturn($organizer);
|
||||
|
||||
$order = $this->createPendingOrder('pi_debt');
|
||||
$this->setBuyerRepo([$order]);
|
||||
|
||||
$paymentIntent = \Stripe\PaymentIntent::constructFrom([
|
||||
'id' => 'pi_debt',
|
||||
'status' => 'succeeded',
|
||||
'amount' => 3000,
|
||||
'metadata' => ['debt_organizer_id' => '42'],
|
||||
]);
|
||||
|
||||
$this->stripeService->method('retrievePaymentIntent')->willReturn($paymentIntent);
|
||||
|
||||
$tester = $this->createCommandTester();
|
||||
$tester->execute([]);
|
||||
|
||||
self::assertStringContainsString('PAID', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testPendingOrderCanceled(): void
|
||||
{
|
||||
$this->userRepo->method('findAll')->willReturn([]);
|
||||
|
||||
$order = $this->createPendingOrder('pi_canceled');
|
||||
$this->setBuyerRepo([$order]);
|
||||
|
||||
$paymentIntent = \Stripe\PaymentIntent::constructFrom([
|
||||
'id' => 'pi_canceled',
|
||||
'status' => 'canceled',
|
||||
]);
|
||||
|
||||
$this->stripeService->method('retrievePaymentIntent')->willReturn($paymentIntent);
|
||||
|
||||
$this->audit->expects(self::once())->method('log')
|
||||
->with('payment_cancelled_sync', 'BilletBuyer', self::anything(), self::anything());
|
||||
|
||||
$tester = $this->createCommandTester();
|
||||
$tester->execute([]);
|
||||
|
||||
self::assertSame(BilletBuyer::STATUS_CANCELLED, $order->getStatus());
|
||||
self::assertStringContainsString('CANCELLED', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testPendingOrderFailed(): void
|
||||
{
|
||||
$this->userRepo->method('findAll')->willReturn([]);
|
||||
|
||||
$order = $this->createPendingOrder('pi_failed');
|
||||
$this->setBuyerRepo([$order]);
|
||||
|
||||
$paymentIntent = \Stripe\PaymentIntent::constructFrom([
|
||||
'id' => 'pi_failed',
|
||||
'status' => 'requires_payment_method',
|
||||
'last_payment_error' => ['message' => 'Card declined'],
|
||||
]);
|
||||
|
||||
$this->stripeService->method('retrievePaymentIntent')->willReturn($paymentIntent);
|
||||
|
||||
$this->audit->expects(self::once())->method('log')
|
||||
->with('payment_failed_sync', 'BilletBuyer', self::anything(), self::anything());
|
||||
$this->mailerService->expects(self::once())->method('sendEmail');
|
||||
|
||||
$tester = $this->createCommandTester();
|
||||
$tester->execute([]);
|
||||
|
||||
self::assertSame(BilletBuyer::STATUS_CANCELLED, $order->getStatus());
|
||||
self::assertStringContainsString('FAILED', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testPendingOrderSkippedWithoutPaymentIntentId(): void
|
||||
{
|
||||
$this->userRepo->method('findAll')->willReturn([]);
|
||||
|
||||
$order = $this->createPendingOrder(null);
|
||||
$this->setBuyerRepo([$order]);
|
||||
|
||||
$this->stripeService->expects(self::never())->method('retrievePaymentIntent');
|
||||
|
||||
$tester = $this->createCommandTester();
|
||||
$tester->execute([]);
|
||||
|
||||
self::assertStringContainsString('SKIP', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testPendingOrderStillPending(): void
|
||||
{
|
||||
$this->userRepo->method('findAll')->willReturn([]);
|
||||
|
||||
$order = $this->createPendingOrder('pi_processing');
|
||||
$this->setBuyerRepo([$order]);
|
||||
|
||||
$paymentIntent = \Stripe\PaymentIntent::constructFrom([
|
||||
'id' => 'pi_processing',
|
||||
'status' => 'processing',
|
||||
]);
|
||||
|
||||
$this->stripeService->method('retrievePaymentIntent')->willReturn($paymentIntent);
|
||||
|
||||
$tester = $this->createCommandTester();
|
||||
$tester->execute([]);
|
||||
|
||||
self::assertSame(BilletBuyer::STATUS_PENDING, $order->getStatus());
|
||||
self::assertStringContainsString('PENDING', $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function testPendingOrderStripeApiError(): void
|
||||
{
|
||||
$this->userRepo->method('findAll')->willReturn([]);
|
||||
|
||||
$order = $this->createPendingOrder('pi_error');
|
||||
$this->setBuyerRepo([$order]);
|
||||
|
||||
$this->stripeService->method('retrievePaymentIntent')
|
||||
->willThrowException(new \RuntimeException('Stripe API error'));
|
||||
|
||||
$tester = $this->createCommandTester();
|
||||
$tester->execute([]);
|
||||
|
||||
self::assertStringContainsString('ERROR', $tester->getDisplay());
|
||||
self::assertSame(1, $tester->getStatusCode());
|
||||
}
|
||||
|
||||
public function testPendingOrderFailedWithoutEmail(): void
|
||||
{
|
||||
$this->userRepo->method('findAll')->willReturn([]);
|
||||
|
||||
$organizer = $this->createOrganizer('acct_no_email');
|
||||
$event = $this->createMock(Event::class);
|
||||
$event->method('getTitle')->willReturn('Test Event');
|
||||
$event->method('getAccount')->willReturn($organizer);
|
||||
|
||||
$order = new BilletBuyer();
|
||||
$order->setStatus(BilletBuyer::STATUS_PENDING);
|
||||
$order->setStripeSessionId('pi_no_email');
|
||||
$order->setEvent($event);
|
||||
|
||||
$this->setBuyerRepo([$order]);
|
||||
|
||||
$paymentIntent = \Stripe\PaymentIntent::constructFrom([
|
||||
'id' => 'pi_no_email',
|
||||
'status' => 'requires_payment_method',
|
||||
'last_payment_error' => null,
|
||||
]);
|
||||
|
||||
$this->stripeService->method('retrievePaymentIntent')->willReturn($paymentIntent);
|
||||
|
||||
$this->audit->expects(self::once())->method('log')
|
||||
->with('payment_failed_sync', 'BilletBuyer', self::anything(), self::anything());
|
||||
$this->mailerService->expects(self::never())->method('sendEmail');
|
||||
|
||||
$tester = $this->createCommandTester();
|
||||
$tester->execute([]);
|
||||
|
||||
self::assertSame(BilletBuyer::STATUS_CANCELLED, $order->getStatus());
|
||||
self::assertStringContainsString('FAILED', $tester->getDisplay());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2049,25 +2049,25 @@ class AccountControllerTest extends WebTestCase
|
||||
|
||||
public function testGetAllowedBilletTypesBasic(): void
|
||||
{
|
||||
$types = \App\Controller\AccountController::getAllowedBilletTypes('basic');
|
||||
$types = \App\Controller\AccountEventCatalogController::getAllowedBilletTypes('basic');
|
||||
self::assertSame(['billet', 'reservation_brocante', 'vote'], $types);
|
||||
}
|
||||
|
||||
public function testGetAllowedBilletTypesSurMesure(): void
|
||||
{
|
||||
$types = \App\Controller\AccountController::getAllowedBilletTypes('sur-mesure');
|
||||
$types = \App\Controller\AccountEventCatalogController::getAllowedBilletTypes('sur-mesure');
|
||||
self::assertSame(['billet', 'reservation_brocante', 'vote'], $types);
|
||||
}
|
||||
|
||||
public function testGetAllowedBilletTypesFree(): void
|
||||
{
|
||||
$types = \App\Controller\AccountController::getAllowedBilletTypes('free');
|
||||
$types = \App\Controller\AccountEventCatalogController::getAllowedBilletTypes('free');
|
||||
self::assertSame(['billet'], $types);
|
||||
}
|
||||
|
||||
public function testGetAllowedBilletTypesNull(): void
|
||||
{
|
||||
$types = \App\Controller\AccountController::getAllowedBilletTypes(null);
|
||||
$types = \App\Controller\AccountEventCatalogController::getAllowedBilletTypes(null);
|
||||
self::assertSame(['billet'], $types);
|
||||
}
|
||||
|
||||
@@ -2750,6 +2750,56 @@ class AccountControllerTest extends WebTestCase
|
||||
self::assertResponseRedirects('/mon-compte/evenement/'.$event->getId().'/modifier?tab=attestation');
|
||||
}
|
||||
|
||||
public function testEventAttestationWithSoldTickets(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$em = static::getContainer()->get(EntityManagerInterface::class);
|
||||
$user = $this->createUser(['ROLE_ORGANIZER'], true);
|
||||
$user->setCompanyName('Test Asso');
|
||||
$user->setSiret('12345678901234');
|
||||
$em->flush();
|
||||
|
||||
$event = $this->createEvent($em, $user);
|
||||
$category = $this->createCategory($em, $event);
|
||||
$billet = $this->createBillet($em, $category);
|
||||
|
||||
$order = new \App\Entity\BilletBuyer();
|
||||
$order->setEvent($event);
|
||||
$order->setFirstName('Jean');
|
||||
$order->setLastName('Dupont');
|
||||
$order->setEmail('jean-att@test.fr');
|
||||
$order->setOrderNumber('T-'.substr(uniqid(), -7));
|
||||
$order->setTotalHT(1000);
|
||||
$order->setStatus(\App\Entity\BilletBuyer::STATUS_PAID);
|
||||
$order->setPaidAt(new \DateTimeImmutable());
|
||||
|
||||
$item = new \App\Entity\BilletBuyerItem();
|
||||
$item->setBillet($billet);
|
||||
$item->setBilletName('Test');
|
||||
$item->setQuantity(2);
|
||||
$item->setUnitPriceHT(500);
|
||||
$order->addItem($item);
|
||||
$em->persist($order);
|
||||
$em->flush();
|
||||
|
||||
$ticket = new \App\Entity\BilletOrder();
|
||||
$ticket->setBilletBuyer($order);
|
||||
$ticket->setBillet($billet);
|
||||
$ticket->setBilletName('Test');
|
||||
$ticket->setUnitPriceHT(500);
|
||||
$em->persist($ticket);
|
||||
$em->flush();
|
||||
|
||||
$client->loginUser($user);
|
||||
$client->request('POST', '/mon-compte/evenement/'.$event->getId().'/attestation', [
|
||||
'categories' => [$category->getId()],
|
||||
'mode' => 'detail',
|
||||
]);
|
||||
|
||||
self::assertResponseIsSuccessful();
|
||||
self::assertStringContainsString('application/pdf', $client->getResponse()->headers->get('Content-Type'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> $roles
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user