Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Korko
SecretSanta.fr
Commits
f18d8f82
Verified
Commit
f18d8f82
authored
Nov 23, 2020
by
Korko
Browse files
Add button in org panel to DL final csv if available
parent
030ffb25
Pipeline
#365306
passed with stages
in 4 minutes and 26 seconds
Changes
38
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
app/Collections/ParticipantsCollection.php
0 → 100755
View file @
f18d8f82
<?php
namespace
App\Collections
;
use
App\Models\Participant
;
use
Illuminate\Database\Eloquent\Collection
as
BaseCollection
;
class
ParticipantsCollection
extends
BaseCollection
{
public
function
appendTargetToExclusions
()
{
return
(
clone
$this
)
->
each
(
function
(
Participant
$participant
)
{
$participant
->
exclusions
->
add
(
$participant
->
target
);
});
}
}
\ No newline at end of file
app/Http/Controllers/OrganizerController.php
View file @
f18d8f82
...
...
@@ -40,6 +40,7 @@ class OrganizerController extends Controller
])
];
}),
'finalCsvAvailable'
=>
$draw
->
next_solvable
]);
}
...
...
@@ -81,7 +82,7 @@ class OrganizerController extends Controller
SendMail
::
dispatch
(
$participant
,
new
TargetDrawn
(
$participant
));
}
public
function
csv
(
Draw
$draw
)
public
function
csv
Init
(
Draw
$draw
)
{
return
response
(
"
\xEF\xBB\xBF
"
.
// UTF-8 BOM
...
...
@@ -94,6 +95,23 @@ class OrganizerController extends Controller
);
}
public
function
csvFinal
(
Draw
$draw
)
{
abort_unless
(
$draw
->
expired
,
403
,
'Cet évènement n\'est pas encore terminé'
);
abort_unless
(
$draw
->
next_solvable
,
404
,
'Cet évènement ne permet pas cette génération'
);
return
response
(
"
\xEF\xBB\xBF
"
.
// UTF-8 BOM
$draw
->
participants
->
appendTargetToExclusions
()
->
toCsv
([
'name'
,
'email'
,
'exclusionsNames'
])
->
prepend
([
[
'# Fichier généré le '
.
date
(
'd-m-Y'
)
.
' sur '
.
config
(
'app.name'
)
.
' ('
.
config
(
'app.url'
)
.
')'
],
[
'# Ce fichier peut être utilisé pour préremplir les participants ainsi que les exclusions associées'
],
])
);
}
public
function
delete
(
Request
$request
,
Draw
$draw
)
{
$draw
->
delete
();
...
...
app/Models/Draw.php
View file @
f18d8f82
...
...
@@ -35,13 +35,6 @@ class Draw extends Model
'expires_at'
,
];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected
$fillable
=
[
'mail_title'
,
'mail_body'
,
'expires_at'
];
public
function
save
(
array
$options
=
[])
{
$this
->
expires_at
=
$this
->
expires_at
?:
(
new
DateTime
(
'now'
))
->
add
(
new
DateInterval
(
'P7D'
));
...
...
@@ -83,7 +76,7 @@ class Draw extends Model
$this
->
resolveHash
(
$value
)
:
parent
::
resolveRouteBinding
(
$value
,
$field
);
abort_if
(
$draw
===
null
||
$draw
->
expired
,
404
);
abort_if
(
$draw
===
null
,
404
);
return
$draw
;
}
...
...
app/Models/Participant.php
View file @
f18d8f82
...
...
@@ -3,6 +3,7 @@
namespace
App\Models
;
use
App\Casts\EncryptedString
;
use
App\Collections\ParticipantsCollection
;
use
Illuminate\Database\Eloquent\Model
;
use
Illuminate\Notifications\Notifiable
;
...
...
@@ -98,4 +99,15 @@ class Participant extends Model
return
$participant
;
}
/**
* Create a new Eloquent Collection instance.
*
* @param array $models
* @return \Illuminate\Database\Eloquent\Collection
*/
public
function
newCollection
(
array
$models
=
[])
{
return
new
ParticipantsCollection
(
$models
);
}
}
app/Services/DrawHandler.php
View file @
f18d8f82
...
...
@@ -43,6 +43,11 @@ class DrawHandler
$this
->
createParticipants
(
$draw
,
$this
->
participants
,
$this
->
hat
);
Metrics
::
increment
(
'participants'
,
count
(
$this
->
participants
));
if
(
!
$this
->
isNextDrawSolvable
(
$draw
))
{
$draw
->
next_solvable
=
false
;
$draw
->
save
();
}
$this
->
sendOrganizerEmail
(
$draw
);
$this
->
sendDelayedOrganizerEmail
(
$draw
);
foreach
(
$draw
->
participants
as
$participant
)
{
...
...
@@ -63,7 +68,6 @@ class DrawHandler
public
function
createParticipants
(
Draw
$draw
,
array
$participants
,
array
$hat
):
void
{
$draw
->
participants
=
collect
();
foreach
(
$participants
as
$idx
=>
$santa
)
{
$mail
=
(
new
MailModel
())
->
draw
()
->
associate
(
$draw
);
$mail
->
save
();
...
...
@@ -76,7 +80,7 @@ class DrawHandler
$participant
->
save
();
$participants
[
$idx
][
'model'
]
=
$participant
;
$draw
->
participants
->
add
(
$participant
);
$draw
->
participants
()
->
save
(
$participant
);
}
foreach
(
$hat
as
$santaIdx
=>
$targetIdx
)
{
...
...
@@ -85,34 +89,38 @@ class DrawHandler
}
$draw
->
participants
[
$santaIdx
]
->
target
()
->
save
(
$participants
[
$targetIdx
][
'model'
]);
$draw
->
participants
[
$santaIdx
]
->
save
();
}
}
public
function
sendOrganizerEmail
(
Draw
$draw
)
public
function
isNextDrawSolvable
(
Draw
$draw
)
:
bool
{
SendMail
::
dispatch
(
$draw
->
organizer
,
new
OrganizerRecap
(
$draw
));
}
try
{
$exclusions
=
[];
public
function
sendDelayedOrganizerEmail
(
Draw
$draw
)
{
$exclusions
=
[];
$draw
->
participant
s
->
each
(
function
(
&
$participant
)
use
(
&
$exclusions
)
{
// We don't attach so not in DB, just in the Collection
$participant
->
exclusions
->
push
(
$participant
->
target
);
$draw
->
participants
->
each
(
function
(
Participant
$participant
)
use
(
&
$exclusions
)
{
$exclusions
[
$participant
->
id
]
=
array_merge
(
$participant
->
exclusions
->
pluck
(
'id'
)
->
all
(),
[
$
participant
->
target
->
id
]
);
}
);
$exclusions
[
$participant
->
id
]
=
$participant
->
exclusions
->
pluck
(
'id'
)
->
all
();
});
Solver
::
one
(
$draw
->
participants
->
pluck
(
null
,
'id'
)
->
all
(),
$exclusions
);
try
{
// Check if there's a solution with the previous exclusions + the actual target
Solver
::
one
(
$draw
->
participants
->
all
(),
$exclusions
);
return
true
;
}
catch
(
SolverException
$exception
)
{
$exclusions
=
[]
;
return
false
;
}
}
public
function
sendOrganizerEmail
(
Draw
$draw
)
{
SendMail
::
dispatch
(
$draw
->
organizer
,
new
OrganizerRecap
(
$draw
));
}
public
function
sendDelayedOrganizerEmail
(
Draw
$draw
)
{
SendMail
::
dispatch
(
$draw
->
organizer
,
new
OrganizerFinalRecap
(
$draw
))
->
delay
(
$draw
->
expires_at
->
addDay
s
(
2
));
->
delay
(
$draw
->
expires_at
->
addDay
(
));
}
public
function
sendParticipantEmail
(
Participant
$participant
)
...
...
app/Solvers/HatSolver.php
View file @
f18d8f82
...
...
@@ -23,7 +23,7 @@ class HatSolver implements SolverInterface
$hat
=
array_keys
(
$participants
);
shuffle
(
$hat
);
return
$this
->
solve
(
0
,
[],
$exclusions
,
$hat
);
return
$this
->
solve
(
array_keys
(
$participants
)[
0
]
,
[],
$exclusions
,
$hat
);
}
private
function
solve
(
int
$participantIdx
,
array
$combination
,
array
$allExclusions
,
array
$currentHat
)
:
Generator
...
...
app/Traits/UpdatesMailDelivery.php
View file @
f18d8f82
...
...
@@ -27,7 +27,8 @@ trait UpdatesMailDelivery
public
function
updateDelivery
(
MailModel
$mail
,
$status
,
$version
=
null
)
{
if
(
!
isset
(
$version
)
or
$mail
->
version
===
(
int
)
$version
)
{
// SQLite does not cast $mail->version as int and $version may be a string too so cast both
if
(
!
isset
(
$version
)
or
(
int
)
$mail
->
version
===
(
int
)
$version
)
{
$mail
->
updateDeliveryStatus
(
$status
);
event
(
new
MailStatusUpdated
(
$mail
));
...
...
database/migrations/2018_12_12_223012_create_draws_table.php
View file @
f18d8f82
...
...
@@ -18,6 +18,7 @@ class CreateDrawsTable extends Migration
$table
->
longText
(
'mail_title'
);
$table
->
longText
(
'mail_body'
);
$table
->
date
(
'expires_at'
);
$table
->
boolean
(
'next_solvable'
)
->
default
(
true
);
$table
->
timestamps
();
});
}
...
...
public/css/404.css
View file @
f18d8f82
...
...
@@ -12082,7 +12082,7 @@ You also need to include this conditional style in the <head> of your HTML file
<!--[if !IE 7]>
<style type="text/css">
#wrap {display:table;height:100%}
#wrap {display:
table;height:
100%}
</style>
<![endif]-->
...
...
@@ -12544,18 +12544,22 @@ footer .row {
13. Tooltip
========================================================================== */
.tip
{
.tip
-wrapper
{
display
:
inline-block
;
position
:
relative
;
border-bottom
:
1px
dotted
#666
;
text-align
:
left
;
}
.tip
h3
{
.tip-wrapper
.tip-handler
{
-webkit-text-decoration
:
underline
dotted
;
text-decoration
:
underline
dotted
;
}
.tip-content
h3
{
margin
:
12px
0
;
}
.tip
.tip-content
{
.tip-content
{
min-width
:
300px
;
max-width
:
400px
;
color
:
#EEEEEE
;
...
...
@@ -12573,47 +12577,47 @@ footer .row {
padding
:
0
;
}
.tip
.right
{
.tip
-content
.right
{
top
:
50%
;
left
:
100%
;
margin-left
:
20px
;
transform
:
translate
(
0
,
-50%
);
}
.tip
.left
{
.tip
-content
.left
{
top
:
50%
;
right
:
100%
;
margin-right
:
20px
;
transform
:
translate
(
0
,
-50%
);
}
.tip
.top
{
.tip
-content
.top
{
top
:
-20px
;
left
:
50%
;
transform
:
translate
(
-30%
,
-100%
);
}
.tip
.bottom
{
.tip
-content
.bottom
{
top
:
40px
;
left
:
50%
;
transform
:
translate
(
-50%
,
0
);
}
.tip
:hover
.tip-content
{
.tip
-wrapper
:hover
.tip-content
{
visibility
:
visible
;
opacity
:
1
;
}
.tip
.tip-content
img
{
.tip-content
img
{
width
:
400px
;
border-radius
:
8px
8px
0
0
;
}
.tip
.text-content
{
.tip
-content
.text-content
{
padding
:
10px
20px
;
}
.tip
.right
i
{
.tip
-content
.right
i
{
position
:
absolute
;
top
:
50%
;
right
:
100%
;
...
...
@@ -12623,7 +12627,7 @@ footer .row {
overflow
:
hidden
;
}
.tip
.right
i
::after
{
.tip
-content
.right
i
::after
{
content
:
""
;
position
:
absolute
;
width
:
12px
;
...
...
@@ -12635,7 +12639,7 @@ footer .row {
box-shadow
:
0
1px
8px
rgba
(
0
,
0
,
0
,
0.5
);
}
.tip
.left
i
{
.tip
-content
.left
i
{
position
:
absolute
;
top
:
50%
;
left
:
100%
;
...
...
@@ -12645,7 +12649,7 @@ footer .row {
overflow
:
hidden
;
}
.tip
.left
i
::after
{
.tip
-content
.left
i
::after
{
content
:
""
;
position
:
absolute
;
width
:
12px
;
...
...
@@ -12657,7 +12661,7 @@ footer .row {
box-shadow
:
0
1px
8px
rgba
(
0
,
0
,
0
,
0.5
);
}
.tip
.top
i
{
.tip
-content
.top
i
{
position
:
absolute
;
top
:
100%
;
left
:
30%
;
...
...
@@ -12667,7 +12671,7 @@ footer .row {
overflow
:
hidden
;
}
.tip
.top
i
::after
{
.tip
-content
.top
i
::after
{
content
:
""
;
position
:
absolute
;
width
:
15px
;
...
...
@@ -12678,7 +12682,7 @@ footer .row {
box-shadow
:
0
1px
8px
rgba
(
0
,
0
,
0
,
0.5
);
}
.tip
.bottom
i
{
.tip
-content
.bottom
i
{
position
:
absolute
;
bottom
:
100%
;
left
:
50%
;
...
...
@@ -12688,7 +12692,7 @@ footer .row {
overflow
:
hidden
;
}
.tip
.bottom
i
::after
{
.tip
-content
.bottom
i
::after
{
content
:
""
;
position
:
absolute
;
width
:
12px
;
...
...
public/css/dearSanta.css
View file @
f18d8f82
...
...
@@ -12080,7 +12080,7 @@ You also need to include this conditional style in the <head> of your HTML file
<!--[if !IE 7]>
<style type="text/css">
#wrap {display:table;height:100%}
#wrap {display:
table;height:
100%}
</style>
<![endif]-->
...
...
@@ -12542,18 +12542,22 @@ footer .row {
13. Tooltip
========================================================================== */
.tip
{
.tip
-wrapper
{
display
:
inline-block
;
position
:
relative
;
border-bottom
:
1px
dotted
#666
;
text-align
:
left
;
}
.tip
h3
{
.tip-wrapper
.tip-handler
{
-webkit-text-decoration
:
underline
dotted
;
text-decoration
:
underline
dotted
;
}
.tip-content
h3
{
margin
:
12px
0
;
}
.tip
.tip-content
{
.tip-content
{
min-width
:
300px
;
max-width
:
400px
;
color
:
#EEEEEE
;
...
...
@@ -12571,47 +12575,47 @@ footer .row {
padding
:
0
;
}
.tip
.right
{
.tip
-content
.right
{
top
:
50%
;
left
:
100%
;
margin-left
:
20px
;
transform
:
translate
(
0
,
-50%
);
}
.tip
.left
{
.tip
-content
.left
{
top
:
50%
;
right
:
100%
;
margin-right
:
20px
;
transform
:
translate
(
0
,
-50%
);
}
.tip
.top
{
.tip
-content
.top
{
top
:
-20px
;
left
:
50%
;
transform
:
translate
(
-30%
,
-100%
);
}
.tip
.bottom
{
.tip
-content
.bottom
{
top
:
40px
;
left
:
50%
;
transform
:
translate
(
-50%
,
0
);
}
.tip
:hover
.tip-content
{
.tip
-wrapper
:hover
.tip-content
{
visibility
:
visible
;
opacity
:
1
;
}
.tip
.tip-content
img
{
.tip-content
img
{
width
:
400px
;
border-radius
:
8px
8px
0
0
;
}
.tip
.text-content
{
.tip
-content
.text-content
{
padding
:
10px
20px
;
}
.tip
.right
i
{
.tip
-content
.right
i
{
position
:
absolute
;
top
:
50%
;
right
:
100%
;
...
...
@@ -12621,7 +12625,7 @@ footer .row {
overflow
:
hidden
;
}
.tip
.right
i
::after
{
.tip
-content
.right
i
::after
{
content
:
""
;
position
:
absolute
;
width
:
12px
;
...
...
@@ -12633,7 +12637,7 @@ footer .row {
box-shadow
:
0
1px
8px
rgba
(
0
,
0
,
0
,
0.5
);
}
.tip
.left
i
{
.tip
-content
.left
i
{
position
:
absolute
;
top
:
50%
;
left
:
100%
;
...
...
@@ -12643,7 +12647,7 @@ footer .row {
overflow
:
hidden
;
}
.tip
.left
i
::after
{
.tip
-content
.left
i
::after
{
content
:
""
;
position
:
absolute
;
width
:
12px
;
...
...
@@ -12655,7 +12659,7 @@ footer .row {
box-shadow
:
0
1px
8px
rgba
(
0
,
0
,
0
,
0.5
);
}
.tip
.top
i
{
.tip
-content
.top
i
{
position
:
absolute
;
top
:
100%
;
left
:
30%
;
...
...
@@ -12665,7 +12669,7 @@ footer .row {
overflow
:
hidden
;
}
.tip
.top
i
::after
{
.tip
-content
.top
i
::after
{
content
:
""
;
position
:
absolute
;
width
:
15px
;
...
...
@@ -12676,7 +12680,7 @@ footer .row {
box-shadow
:
0
1px
8px
rgba
(
0
,
0
,
0
,
0.5
);
}
.tip
.bottom
i
{
.tip
-content
.bottom
i
{
position
:
absolute
;
bottom
:
100%
;
left
:
50%
;
...
...
@@ -12686,7 +12690,7 @@ footer .row {
overflow
:
hidden
;
}
.tip
.bottom
i
::after
{
.tip
-content
.bottom
i
::after
{
content
:
""
;
position
:
absolute
;
width
:
12px
;
...
...
public/css/faq.css
View file @
f18d8f82
...
...
@@ -12080,7 +12080,7 @@ You also need to include this conditional style in the <head> of your HTML file
<!--[if !IE 7]>
<style type="text/css">
#wrap {display:table;height:100%}
#wrap {display:
table;height:
100%}
</style>
<![endif]-->
...
...
@@ -12542,18 +12542,22 @@ footer .row {
13. Tooltip
========================================================================== */
.tip
{
.tip
-wrapper
{
display
:
inline-block
;
position
:
relative
;
border-bottom
:
1px
dotted
#666
;
text-align
:
left
;
}
.tip
h3
{
.tip-wrapper
.tip-handler
{
-webkit-text-decoration
:
underline
dotted
;
text-decoration
:
underline
dotted
;
}
.tip-content
h3
{
margin
:
12px
0
;
}
.tip
.tip-content
{
.tip-content
{
min-width
:
300px
;
max-width
:
400px
;
color
:
#EEEEEE
;
...
...
@@ -12571,47 +12575,47 @@ footer .row {
padding
:
0
;
}
.tip
.right
{
.tip
-content
.right
{
top
:
50%
;
left
:
100%
;
margin-left
:
20px
;
transform
:
translate
(
0
,
-50%
);
}
.tip
.left
{
.tip
-content
.left
{
top
:
50%
;
right
:
100%
;
margin-right
:
20px
;
transform
:
translate
(
0
,
-50%
);
}
.tip
.top
{
.tip
-content
.top
{
top
:
-20px
;
left
:
50%
;
transform
:
translate
(
-30%
,
-100%
);
}
.tip
.bottom
{
.tip
-content
.bottom
{
top
:
40px
;
left
:
50%
;
transform
:
translate
(
-50%
,
0
);
}
.tip
:hover
.tip-content
{
.tip
-wrapper
:hover
.tip-content
{
visibility
:
visible
;
opacity
:
1
;
}
.tip
.tip-content
img
{
.tip-content
img
{
width
:
400px
;
border-radius
:
8px
8px
0
0
;
}
.tip
.text-content
{
.tip
-content
.text-content
{
padding
:
10px
20px
;
}
.tip
.right
i
{
.tip
-content
.right
i
{
position
:
absolute
;
top
:
50%
;
right
:
100%
;
...
...
@@ -12621,7 +12625,7 @@ footer .row {
overflow
:
hidden
;
}
.tip
.right
i
::after
{
.tip
-content
.right
i
::after
{