Refactoring du processus d'import par url:

- on utilise tout le temps celery
- on propose un import par lot
- on remercie l'utilisateur et on l'informe des urls prises en compte ou non
This commit is contained in:
Jean-Marie Favreau 2024-08-15 22:32:42 +02:00
parent b9c63219bb
commit ca1db6890d
9 changed files with 675 additions and 402 deletions

View File

@ -199,6 +199,45 @@ def weekly_imports(self):
run_recurrent_import.delay(imp.pk) run_recurrent_import.delay(imp.pk)
@app.task(base=ChromiumTask, bind=True)
def import_events_from_urls(self, urls_and_cats):
from agenda_culturel.models import Event, Category
for ucat in urls_and_cats:
if ucat is not None:
url = ucat[0]
cat = ucat[1]
url = Extractor.clean_url(url)
# we check if the url is known
existing = Event.objects.filter(uuids__contains=[url])
# if it's unknown
if len(existing) == 0:
u2e = URL2Events(ChromiumHeadlessDownloader(), single_event=True)
events_structure = u2e.process(
url, published=False
)
# TODO: use celery to import the associated events
if (
events_structure is not None
and "events" in events_structure
and len(events_structure["events"]) > 0
):
event = Event.from_structure(
events_structure["events"][0],
events_structure["header"]["url"],
)
if event is not None:
if (event.category is None or event.category == Category.get_default_category()):
if cat is not None:
event.category = Category.objects.filter(name=cat).first()
event.save()
logger.info('Successful import from ' + url)
app.conf.beat_schedule = { app.conf.beat_schedule = {
"daily_imports": { "daily_imports": {
"task": "agenda_culturel.celery.daily_imports", "task": "agenda_culturel.celery.daily_imports",

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="96.291573mm"
height="56.166805mm"
viewBox="0 0 96.291582 56.166805"
version="1.1"
id="svg5"
xml:space="preserve"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
sodipodi:docname="merci.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="1.3189567"
inkscape:cx="104.24906"
inkscape:cy="-20.091638"
inkscape:window-width="1920"
inkscape:window-height="1020"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g384" /><defs
id="defs2"><filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter38466-3"
x="-0.060800897"
y="-0.25262014"
width="1.1216247"
height="1.5052374"><feGaussianBlur
inkscape:collect="always"
stdDeviation="0.81073628"
id="feGaussianBlur38468-6" /></filter><filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter38466-3-5"
x="-0.060800895"
y="-0.25262014"
width="1.1216247"
height="1.5052374"><feGaussianBlur
inkscape:collect="always"
stdDeviation="0.81073628"
id="feGaussianBlur38468-6-3" /></filter></defs><g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-56.292353,-59.875625)"><g
id="g384"
transform="translate(22.72439,-118.49779)"><path
style="fill:#008000;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 78.595236,189.74139 c 1.637421,-4.59024 2.912742,-7.06191 5.749725,-8.47307 5.268285,-2.62054 9.623617,-2.69186 15.476304,-2.08514 3.422645,0.35481 6.886145,2.32348 9.257535,4.56744 -6.13616,1.90424 -8.28801,4.46745 -12.838753,5.36178 -5.774877,1.13491 -11.763207,0.41933 -17.644811,0.62899"
id="path1596"
sodipodi:nodetypes="cccccc" /><path
style="fill:#010000;fill-opacity:0.561232;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter38466-3)"
d="m 61.796221,229.14122 c 0.965519,4.45831 25.019863,3.96877 30.482693,1.22894 13.879366,-2.9076 -16.08645,-5.72863 -22.936483,-6.13413 -4.613953,0.0322 -8.095357,1.93397 -7.54621,4.90519 z"
id="path38464-7"
sodipodi:nodetypes="cccc" /><path
style="fill:#010000;fill-opacity:0.561232;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter38466-3-5)"
d="m 39.807813,223.56146 c 0.965519,4.45831 25.019863,3.96877 30.482693,1.22894 13.879368,-2.9076 -16.08645,-5.72863 -22.936483,-6.13413 -4.613953,0.0322 -8.095357,1.93397 -7.54621,4.90519 z"
id="path38464-7-5"
sodipodi:nodetypes="cccc" /><path
style="fill:#840103;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 61.349027,222.15794 c 0.708759,2.00893 -16.515833,0.34774 -21.687027,-7.93835 -5.171194,-8.2861 -3.763967,-13.58169 -2.234075,-17.59746 1.529892,-4.01577 2.907438,-5.92547 5.806876,-8.7927 2.899438,-2.86723 5.998448,-8.59829 11.9153,-8.91316 5.916851,-0.31487 13.246677,1.03438 18.14476,6.51896 4.898083,5.48457 4.135783,4.56309 4.327753,11.82129 0.19197,7.2582 -16.982346,22.89249 -16.273587,24.90142 z"
id="path38521"
sodipodi:nodetypes="zzzzzzzz" /><path
style="fill:#a30b0e;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 65.673042,229.32826 c 0,0 2.096979,0.98865 3.366175,1.05833 1.269196,0.0697 2.515497,-0.62306 4.020413,-0.79375 1.504916,-0.17069 3.315514,-0.33009 4.986984,-0.15445 1.67146,0.17564 2.67655,1.44596 4.94818,1.21279 2.27163,-0.23317 4.7873,-0.53519 7.76883,-3.24162 2.98153,-2.70643 6.67077,-9.99926 8.01766,-13.7903 1.346886,-3.79104 0.964,-6.95292 0.88227,-8.76492 -0.0817,-1.812 -0.28545,-2.05058 -0.28545,-2.05058"
id="path6267"
sodipodi:nodetypes="czzzzzzzc" /><path
style="fill:#c07f16;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 71.812371,190.61847 c 1.858659,0.51169 3.166323,1.18081 5.616683,1.52344 1.36291,-0.20833 2.52486,-0.13533 4.31769,-0.94554 l -1.36453,9.43662 c 0,0 -6.727792,0.0977 -6.541247,-0.54771 0.186544,-0.6454 -2.028596,-9.46681 -2.028596,-9.46681 z"
id="path24930"
sodipodi:nodetypes="ccccsc" /><path
style="fill:#f1e890;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 78.082684,198.37205 c -1.28283,-3.55228 -5.226566,-9.29945 -10.596971,-8.55496 -5.370405,0.74449 -10.078575,7.90246 -10.928331,15.43409 -0.849756,7.53163 7.401814,24.34497 10.192223,24.52944 3.229996,0.55392 5.958819,-1.60562 6.699335,-2.56442 0.740516,-0.9588 1.0542,1.41933 1.880334,1.58911 0.82614,0.16978 1.47736,-1.00863 2.48529,-0.75867 1.00793,0.24996 4.01972,2.24324 6.05234,1.00663 8.40879,-5.32292 15.92933,-15.39837 15.55298,-25.19132 -0.22977,-5.9788 -4.35586,-13.60403 -10.22824,-14.75036 -6.96794,-1.3602 -9.33036,3.99209 -11.10896,9.26046 z"
id="path6257"
sodipodi:nodetypes="czzczzzcssc" /><path
style="fill:#744e0b;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 77.313734,188.64368 -0.42521,-1.38416 0.9446,-0.48098 0.84134,0.21637 0.0662,5.23515 v 3.40759 c -0.36705,0.23459 -0.84847,0.0157 -1.32294,-0.17562 -3e-5,-0.13276 -0.10399,-6.81835 -0.10399,-6.81835 z"
id="path6259"
sodipodi:nodetypes="cccccccc" /><path
style="fill:#60140f;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 82.946843,205.63036 c -0.10793,0.44487 -0.0918,0.80693 -0.0505,1.30309 0.0413,0.49616 -0.27564,1.44483 0.34253,1.64797 0.61817,0.20314 1.44979,-0.60075 1.65368,-1.48252 0.20389,-0.88177 -1.27069,-2.87462 -1.27069,-2.87462 0,0 -0.56709,0.96121 -0.67502,1.40608 z"
id="path6261"
sodipodi:nodetypes="zzzzcz" /><path
style="fill:#60140f;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 72.30932,204.58819 c -0.53143,0.0298 -0.217288,0.3086 -0.396875,0.76536 -0.179587,0.45676 -0.855987,1.48491 -0.557202,2.00672 0.298785,0.52181 1.011637,0.57281 1.473936,0.39196 0.462302,-0.18085 0.786262,-0.59664 0.778252,-1.22739 -0.008,-0.63075 -0.766681,-1.96648 -1.298111,-1.93665 z"
id="path6263"
sodipodi:nodetypes="zzzzzz" /><path
style="fill:#f5dc0c;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 77.682294,200.72052 -0.81262,4.57009 -0.31681,6.97364 0.99998,3.92596 0.75482,-4.71212 -0.0384,-3.55499 z"
id="path6265" /><path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 41.991603,198.95761 c 0,0 4.204417,-1.16049 5.95753,-1.68797 0.53786,-0.16183 0.794335,-3.57452 0.695045,-3.97169 -0.09929,-0.39717 -1.092213,-2.4823 -1.092213,-2.4823"
id="path39627"
sodipodi:nodetypes="cszc" /><path
style="fill:#510701;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 47.80348,196.5405 c -0.105315,-0.14042 -1.841212,-1.73181 -2.632882,-2.7733 -0.79167,-1.04149 -1.693987,-2.52693 -2.071198,-3.45155 -0.377211,-0.92462 -0.738993,-1.48616 -0.456366,-1.91264 0.282627,-0.42648 0.734231,-0.30422 1.088257,-0.18241 0.354026,0.12181 0.684882,0.55237 0.772311,0.84252 0.08743,0.29015 -0.119676,0.3973 -0.105315,0.667 0.01436,0.2697 -0.04559,0.27495 0.245735,0.91273 0.291328,0.63778 1.160067,1.94648 1.825466,2.70309 0.665399,0.75661 1.859099,1.04674 2.088991,1.83989 0.229892,0.79315 -0.09265,2.0968 -0.609346,2.08381 -0.516692,-0.013 -0.215863,-0.90466 -0.215863,-0.90466"
id="path39629"
sodipodi:nodetypes="czzzzzzzzzzc" /><path
style="fill:#ff6600;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 103.98789,206.44948 -5.111645,15.83899 c 0,0 6.647825,-5.08721 5.653415,-2.65705 -2.93215,7.16558 3.44504,-11.15811 3.44504,-11.15811 z"
id="path3853"
sodipodi:nodetypes="ccscc" /><g
id="g1540"
transform="rotate(18.710832,138.65558,232.66702)"><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
id="rect624"
width="37.333855"
height="22.292042"
x="80.918617"
y="198.86351"
ry="3.0437441" /><g
aria-label="Merci !"
id="text1442"
style="font-weight:bold;font-size:9.51886px;font-family:'Comic Sans MS';-inkscape-font-specification:'Comic Sans MS, Bold';stroke-width:0.238347"><path
d="m 86.718914,209.92516 q -0.209154,0.75296 -0.585633,2.27281 -0.08831,0.52521 -0.171971,1.04578 -0.190564,0.65999 -0.70183,0.65999 -0.320704,0 -0.506619,-0.21845 -0.158028,-0.18591 -0.158028,-0.44154 0,-0.75296 0.320703,-1.83592 0.478732,-1.62211 0.515915,-1.79873 0.134789,-0.71577 0.274225,-1.43154 0.209155,-0.98535 0.450845,-1.31071 0.246337,-0.33 0.618168,-0.33 0.422957,0 0.622816,0.42761 0.185915,0.40436 0.399718,1.65464 0.204506,1.2131 0.608872,2.61211 0.529858,-1.38042 0.985351,-3.03041 l 0.260281,-1.06902 q 0.250986,-0.66464 0.776196,-0.66464 0.506619,0 0.752957,0.77154 0.102253,0.31141 0.21845,1.16197 0.269577,1.98 0.678591,3.39296 0.413661,1.43619 0.413661,1.56169 0,0.27422 -0.21845,0.46014 -0.204507,0.16732 -0.46014,0.16732 -0.506619,0 -0.752957,-0.72507 l -0.260281,-1.12479 q -0.223099,-0.83662 -0.48338,-2.40295 -0.209155,0.62281 -0.692534,1.95676 l -0.278873,0.85521 q -0.171972,0.50661 -0.357887,0.83197 -0.246338,0.43225 -0.687886,0.43225 -0.436901,0 -0.669295,-0.51592 l -0.260282,-0.8645 q -0.362534,-1.18986 -0.650703,-2.50056 z"
id="path1507" /><path
d="m 95.480169,213.81079 q -1.110844,0 -1.817321,-0.52986 -0.780844,-0.58563 -0.780844,-1.65 0,-1.17591 0.618168,-1.98929 0.687886,-0.90169 1.854504,-0.90169 0.808731,0 1.343238,0.26028 0.70183,0.34394 0.70183,1.06901 0,0.51127 -0.57169,0.90634 -0.260281,0.18127 -1.045773,0.52986 l -1.566336,0.69253 q 0.223099,0.24169 0.539155,0.36254 0.316055,0.12084 0.725069,0.12084 0.622816,0 1.055069,-0.25563 0.385774,-0.22775 0.618168,-0.22775 0.48338,0 0.48338,0.46944 0,0.52986 -0.776196,0.8645 -0.650704,0.27888 -1.380421,0.27888 z m -0.125493,-3.94605 q -0.432253,0 -0.739013,0.28817 -0.30676,0.28816 -0.492675,0.8645 0.52521,-0.22775 1.045773,-0.45084 0.627464,-0.28352 0.999294,-0.52521 -0.311408,-0.17662 -0.813379,-0.17662 z"
id="path1509" /><path
d="m 102.35438,210.24586 q -0.0418,0.71113 -0.64605,0.71113 -0.58563,0 -0.58563,-0.60423 l -0.0232,-0.46943 q -1.04578,0.16732 -1.496621,1.07366 l 0.0046,2.33788 q 0,0.26493 -0.181268,0.4369 -0.181267,0.17662 -0.46014,0.17662 -0.288168,0 -0.446196,-0.18591 -0.148733,-0.16733 -0.148733,-0.42761 v -3.04436 q 0,-0.14408 0.0093,-0.4276 0.0093,-0.28817 0.0093,-0.43226 0,-0.26028 0.15338,-0.43225 0.158028,-0.17662 0.446197,-0.17662 0.515914,0 0.61352,0.52986 0.822671,-0.61352 1.826621,-0.61352 0.92957,0 0.92957,1.23633 0,0.23705 -0.005,0.31141 z"
id="path1511" /><path
d="m 105.171,213.8898 q -1.02253,0 -1.71507,-0.58098 -0.72971,-0.61352 -0.72971,-1.61747 0,-0.92492 0.65535,-1.91028 0.74366,-1.12478 1.72901,-1.12478 0.48338,0 1.12943,0.26028 0.78549,0.3207 0.78549,0.73901 0,0.22775 -0.15802,0.40437 -0.16733,0.19056 -0.43226,0.19056 -0.19985,0 -0.48338,-0.2138 -0.27887,-0.21845 -0.84126,-0.21845 -0.35789,0 -0.7762,0.70183 -0.39972,0.67859 -0.39972,1.17126 0,0.48803 0.35324,0.7669 0.33465,0.26493 0.8831,0.26493 0.31141,0 0.76225,-0.23704 0.45085,-0.23704 0.57169,-0.23704 0.25099,0 0.42761,0.18127 0.18126,0.18126 0.18126,0.41366 0,0.36253 -0.79014,0.72507 -0.70647,0.3207 -1.15267,0.3207 z"
id="path1513" /><path
d="m 108.98226,208.01023 q -0.29746,0 -0.51591,-0.19986 -0.21845,-0.19986 -0.21845,-0.48802 0,-0.28817 0.21845,-0.48803 0.21845,-0.19986 0.51591,-0.19986 0.29747,0 0.51127,0.19986 0.21845,0.19986 0.21845,0.48803 0,0.28816 -0.21845,0.48802 -0.2138,0.19986 -0.51127,0.19986 z m 0.39507,3.4069 q 0,0.26493 0.0139,0.85056 0.0186,0.58563 0.0186,0.85056 0,0.26958 -0.18127,0.4462 -0.18127,0.17197 -0.46014,0.17197 -0.27887,0 -0.46014,-0.17197 -0.18127,-0.17662 -0.18127,-0.4462 0,-0.26493 -0.0186,-0.85056 -0.0139,-0.58563 -0.0139,-0.85056 0,-0.41366 0.0465,-1.03648 0.0465,-0.62281 0.0465,-1.03648 0,-0.26957 0.18126,-0.44154 0.18127,-0.17662 0.46014,-0.17662 0.27888,0 0.46014,0.17662 0.18127,0.17197 0.18127,0.44154 0,0.41367 -0.0465,1.03648 -0.0465,0.62282 -0.0465,1.03648 z"
id="path1515" /><path
d="m 115.36845,212.21656 q -0.26028,0 -0.43225,-0.16267 -0.16733,-0.16268 -0.16733,-0.40902 0,-0.18126 -0.0139,-0.53915 -0.009,-0.36253 -0.009,-0.5438 0,-0.64141 0.009,-1.92422 0.0139,-1.28282 0.0139,-1.92423 0,-0.24633 0.17198,-0.40901 0.17197,-0.16732 0.4276,-0.16732 0.25563,0 0.42761,0.16732 0.17197,0.16268 0.17197,0.40901 v 4.9314 q 0,0.24634 -0.17197,0.40902 -0.16733,0.16267 -0.42761,0.16267 z m -0.0139,1.68718 q -0.27888,0 -0.52057,-0.29746 -0.21845,-0.27422 -0.21845,-0.51127 0,-0.24169 0.19057,-0.40436 0.19056,-0.16268 0.43225,-0.16268 0.27887,0 0.51592,0.29747 0.21845,0.27422 0.21845,0.50662 0,0.23704 -0.19057,0.40436 -0.18591,0.16732 -0.4276,0.16732 z"
id="path1517" /></g></g><path
style="fill:#007700;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 43.963481,192.38257 c -8.814017,3.40711 -10.967105,13.7965 -9.43133,18.16737 1.535776,4.37087 2.112699,8.01053 6.643607,9.05239 -1.873669,-6.18344 -0.699401,-9.06026 -0.247367,-13.55754 0.466564,-4.6417 3.297172,-7.78272 3.03509,-13.66222"
id="path1596-0"
sodipodi:nodetypes="czcac" /><path
d="m 94.587389,218.65885 c 0,0 0.953693,-5.7278 5.877331,-6.4571 0,0 4.46881,0.76778 4.5444,2.17455 0,0 4.70056,-0.0156 3.84696,3.2503 0,0 -0.0752,1.38167 -1.38138,1.78383 0,0 2.51238,1.65759 0.30205,3.76813 l -1.85882,0.92978 c 0,0 0.95503,2.63758 -2.05946,3.06512 0,0 -1.02987,0.60307 -2.26096,-0.37646 0,0 -4.069454,1.18135 -6.406305,-2.46086 0,0 -1.808924,-1.23065 -0.603816,-5.67729"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-dasharray:none;stroke-opacity:1"
id="path2902" /><path
d="m 94.587389,218.65885 c 0,0 0.953693,-5.7278 5.877331,-6.4571 0,0 4.40973,0.63603 4.48532,2.0428 0,0 4.75964,0.11615 3.90604,3.38205 0,0 -0.0752,1.38167 -1.38138,1.78383 0,0 2.51238,1.65759 0.30205,3.76813 l -1.85882,0.92978 c 0,0 0.95503,2.63758 -2.05946,3.06512 0,0 -1.02987,0.60307 -2.26096,-0.37646 0,0 -4.069454,1.18135 -6.406305,-2.46086 0,0 -1.808924,-1.23065 -0.603816,-5.67729 z"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
id="path2904"
sodipodi:nodetypes="ccccccccccc" /><path
d="m 104.95004,214.24455 c 0.12844,1.47744 -0.91771,2.46285 -1.55157,3.58466 -0.73408,1.29954 -0.19399,3.72087 -2.23543,3.93879 -4.443922,0.47457 -2.310651,-6.60468 -0.33428,-7.34448"
style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
id="path2906"
sodipodi:nodetypes="cccc" /><path
d="m 98.668772,217.16207 c -0.496418,-0.43585 -0.540213,-1.12366 -0.32686,-1.75843"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
id="path2908" /><path
d="m 107.4747,219.41043 c -1.16386,0.58644 -4.29829,0.35908 -4.4022,-0.65987"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
id="path2910"
sodipodi:nodetypes="cc" /><path
d="m 106.73371,223.61694 c -2.06624,0.79858 -4.07457,0.11332 -4.97428,-1.75769"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
id="path2912" /><path
style="fill:#ff6600;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 98.876245,222.28847 v 0 l -1.624195,5.28296 c -0.12264,1.25072 3.60773,2.76629 3.83615,1.12175 0.005,-0.0357 0.30602,-0.79593 0.66435,-1.79926 -3.37616,-3.34464 -1.42049,-4.22503 -2.876305,-4.60545 z"
id="path3853-6-4"
sodipodi:nodetypes="cccscc" /><path
d="m 100.08014,221.79543 c -1.90604,1.60694 1.81991,5.20252 1.67241,5.09849"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
id="path2914"
sodipodi:nodetypes="cc" /><path
d="m 98.945728,221.08094 c -0.494546,0.24978 -1.143288,0.65344 -1.783528,0.47759"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
id="path2916" /><path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 99.192188,221.24361 v 0 l -1.940147,6.32782 c -0.26565,1.38741 3.497779,2.57455 3.836159,1.12175 0.008,-0.0351 0.30602,-0.79593 0.66435,-1.79926"
id="path3853-6"
sodipodi:nodetypes="cccsc" /></g></g></svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -23,7 +23,8 @@
<p>On peut importer automatiquement un événement depuis d'autres sites internet (principalement depuis Facebook pour <p>On peut importer automatiquement un événement depuis d'autres sites internet (principalement depuis Facebook pour
l'instant), à partir de l'adresse (url) de la page de l'événement. l'instant), à partir de l'adresse (url) de la page de l'événement.
</p> </p>
<a href="{% url 'add_event_url' %}" role="button" class="large">Importer depuis une url</a> <a href="{% url 'add_event_url' %}" role="button" class="large">Importer un événement depuis son url</a>
<a href="{% url 'add_event_urls' %}" role="button" class="large">Importer des événements depuis leurs urls</a>
<p>Si l'événement n'est pas disponible en ligne, ou si l'import ne fonctionne pas, on peut <p>Si l'événement n'est pas disponible en ligne, ou si l'import ne fonctionne pas, on peut
ajouter un événement en utilisant un formulaire complet. ajouter un événement en utilisant un formulaire complet.

View File

@ -4,20 +4,6 @@
{% load static %} {% load static %}
{% block entete_header %}
<script src="{% url 'jsi18n' %}"></script>
<script src="/static/admin/js/vendor/jquery/jquery.js"></script>
<script src="/static/admin/js/jquery.init.js"></script>
<script src="/static/admin/js/admin/DateTimeShortcuts.js"></script>
<script src="{% static 'recurrence/js/recurrence.js' %}"></script>
<script src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script src="{% static 'recurrence/js/recurrence-widget.js' %}"></script>
<script src="{% static 'recurrence/js/recurrence-widget.init.js' %}"></script>
<script src="{% static 'js/modal.js' %}"></script>
{% endblock %}
{% block fluid %}{% endblock %} {% block fluid %}{% endblock %}
@ -26,7 +12,7 @@
<article> <article>
<header> <header>
<h1>Importer un événement</h1> <h1>Importer un événement</h1>
{% url 'event_import_form' as local_url %} {% url 'event_import_url' as local_url %}
{% include "agenda_culturel/static_content.html" with name="import" url_path=local_url %} {% include "agenda_culturel/static_content.html" with name="import" url_path=local_url %}
</header> </header>
<div id="container"></div> <div id="container"></div>
@ -34,15 +20,13 @@
{% csrf_token %} {% csrf_token %}
{{ form.media }} {{ form.media }}
{{ form.as_p }} {{ form.as_p }}
<input type="submit" value="Lancer l'import" id="import-button" data-target="modal-import" onClick="toggleModalNoEscape(event)"> <input type="submit" value="Lancer l'import" id="import-button">
</form> </form>
<p>Si tu as plein d'événements à ajouter, tu peux les <a href="{% url 'add_event_urls' %}" >ajouter par lots</a>.</p>
<p>Si l'import automatique ne marche pas, ou si l'événement n'est pas en ligne, vous pouvez
<p>Si l'import automatique ne marche pas, ou si l'événement n'est pas en ligne, tu peux
tout de même ajouter l'événement en le décrivant sur la page <a href="{% url 'add_event_details' %}" >d'ajout d'événement</a>.</p> tout de même ajouter l'événement en le décrivant sur la page <a href="{% url 'add_event_details' %}" >d'ajout d'événement</a>.</p>
</article> </article>
<dialog id="modal-import">
<article aria-busy="true">
Veuillez patienter, lien en cours d'importation...
</article>
</dialog>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,38 @@
{% extends "agenda_culturel/page.html" %}
{% block title %}Importer un ensemble d'événements{% endblock %}
{% load static %}
{% block fluid %}{% endblock %}
{% block content %}
<article>
<header>
<h1>Importer un ensemble d'événements</h1>
{% url 'event_import_urls' as local_url %}
{% include "agenda_culturel/static_content.html" with name="import_set" url_path=local_url %}
</header>
<form method="post">
{{ formset.management_form }}
{% csrf_token %}
{% for form in formset %}
<h2>Nouvel événement #{{ forloop.counter }}</h2>
{{ form.as_p }}
{% endfor %}
<input type="submit" value="Lancer l'import" id="import-button">
</form>
<p>Si l'import automatique ne marche pas, ou si l'événement n'est pas en ligne, vous pouvez
tout de même ajouter l'événement en le décrivant sur la page <a href="{% url 'add_event_details' %}" >d'ajout d'événement</a>.</p>
</article>
<dialog id="modal-import">
<article aria-busy="true">
Veuillez patienter, lien en cours d'importation...
</article>
</dialog>
{% endblock %}

View File

@ -0,0 +1,32 @@
{% extends "agenda_culturel/page.html" %}
{% block title %}Merci !{% endblock %}
{% load static %}
{% block entete_header %}
<script src="{% static 'js/modal.js' %}"></script>
{% endblock %}
{% block fluid %}{% endblock %}
{% block content %}
<article>
<header>
<h1>Merci !</h1>
{% url 'thank_you' as local_url %}
</header>
<div class="grid two-columns-2">
<div class="image"><img src="{% static 'images/merci.svg' %}" alt="quelques pommes et leur pépins" /></div>
<div>
{% include "agenda_culturel/static_content.html" with name="thank-you" url_path=local_url %}
<!-- p>Merci d'avoir ramené ta pomme, et participé à améliorer l'agenda culturel&nbsp;!</p>
<p>N'oublie pas de partager autour de toi les pommes de lune, pour qu'il devienne petit à petit
l'adresse où trouver toutes les activités de Clermont-Ferrand et des environs.</p-->
</div>
</div>
</article>
{% endblock %}

View File

@ -39,6 +39,7 @@ urlpatterns = [
path("event/<int:pk>/moderate", EventModerateView.as_view(), name="moderate_event"), path("event/<int:pk>/moderate", EventModerateView.as_view(), name="moderate_event"),
path("ajouter", import_event_proxy, name="add_event"), path("ajouter", import_event_proxy, name="add_event"),
path("ajouter/url", import_from_url, name="add_event_url"), path("ajouter/url", import_from_url, name="add_event_url"),
path("ajouter/urls", import_from_urls, name="add_event_urls"),
path("ajouter/details", EventCreateView.as_view(), name="add_event_details"), path("ajouter/details", EventCreateView.as_view(), name="add_event_details"),
path("admin/", admin.site.urls), path("admin/", admin.site.urls),
path("accounts/", include("django.contrib.auth.urls")), path("accounts/", include("django.contrib.auth.urls")),
@ -57,6 +58,7 @@ urlpatterns = [
path("rechercher/complet/", event_search_full, name="event_search_full"), path("rechercher/complet/", event_search_full, name="event_search_full"),
path("mentions-legales", mentions_legales, name="mentions_legales"), path("mentions-legales", mentions_legales, name="mentions_legales"),
path("a-propos", about, name="about"), path("a-propos", about, name="about"),
path("merci", thank_you, name="thank_you"),
path("contact", ContactMessageCreateView.as_view(), name="contact"), path("contact", ContactMessageCreateView.as_view(), name="contact"),
path("contactmessages", contactmessages, name="contactmessages"), path("contactmessages", contactmessages, name="contactmessages"),
path( path(

View File

@ -14,6 +14,8 @@ from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse from django.urls import reverse
from collections import Counter from collections import Counter
from django.forms import formset_factory
from .forms import ( from .forms import (
URLSubmissionForm, URLSubmissionForm,
EventForm, EventForm,
@ -46,6 +48,7 @@ from .models import (
Place, Place,
) )
from django.utils import timezone from django.utils import timezone
from django.utils.html import escape
from datetime import date, timedelta from datetime import date, timedelta
from django.db.models import Q from django.db.models import Q
@ -69,6 +72,7 @@ from .celery import (
import_events_from_json, import_events_from_json,
run_recurrent_import, run_recurrent_import,
run_all_recurrent_imports, run_all_recurrent_imports,
import_events_from_urls,
) )
import urllib import urllib
@ -122,7 +126,6 @@ to_be_translated = [
_("Recurrent import name"), _("Recurrent import name"),
_("Add another"), _("Add another"),
_("Browse..."), _("Browse..."),
_("Naviguer..."),
_("No file selected."), _("No file selected."),
] ]
@ -141,6 +144,9 @@ def page_not_found(request, exception=None):
def internal_server_error(request): def internal_server_error(request):
return render(request, "page-erreur.html", status=500, context={"error": 500}) return render(request, "page-erreur.html", status=500, context={"error": 500})
def thank_you(request):
return render(request, "agenda_culturel/thank_you.html")
class CategoryCheckboxSelectMultiple(forms.CheckboxSelectMultiple): class CategoryCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
template_name = "agenda_culturel/forms/category-checkbox.html" template_name = "agenda_culturel/forms/category-checkbox.html"
@ -548,155 +554,162 @@ def import_from_details(request):
request, "agenda_culturel/event_form.html", context={"form": form} request, "agenda_culturel/event_form.html", context={"form": form}
) )
# A class to evaluate the URL according to the existing events and the authentification
# level of the user
class URLEventEvaluation:
def import_from_url(request): def __init__(self, form, is_authenticated):
import logging self.form = form
self.is_authenticated = is_authenticated
logging.getLogger(__name__) self.cat = None
self.existing = None
self.url = form.cleaned_data.get('url')
self.event = None
if self.url is not None:
self.url = Extractor.clean_url(self.url)
# we check if the url is known
self.existing = Event.objects.filter(uuids__contains=[self.url])
# if it's unknown
if len(self.existing) == 0:
self.existing = None
self.cat = form.cleaned_data.get('category')
if self.cat is not None:
self.cat = self.cat.name
# if a form has been sent and contains an event
if request.method == "POST" and "title" in request.POST:
# the result of this form is checked
form = EventForm(request.POST, is_authenticated=request.user.is_authenticated)
if form.is_valid():
new_event = form.save()
if request.user.is_authenticated:
messages.success(request, _("The event is saved."))
return HttpResponseRedirect(new_event.get_absolute_url())
else: else:
messages.success( published = [
request, e for e in self.existing if e.status == Event.STATUS.PUBLISHED
_( ]
"The event has been submitted and will be published as soon as it has been validated by the moderation team." drafts = [e for e in self.existing if e.status == Event.STATUS.DRAFT]
), trash = [e for e in self.existing if e.status == Event.STATUS.TRASH]
)
return HttpResponseRedirect(reverse("home"))
else:
return render(
request, "agenda_culturel/event_form.html", context={"form": form}
)
else: if self.is_authenticated or len(published) > 1:
form = URLSubmissionForm() self.event = published[0] if len(published) > 1 else self.existing[0]
initial = {
"start_day": date.today() + timedelta(days=1),
"start_time": "20:00",
"end_time": "22:00",
}
form_event = EventForm(initial=initial)
# if the form has been sent
if request.method == "POST":
form = URLSubmissionForm(request.POST)
# if the form is valid
if form.is_valid():
# the url is cleaned
cd = form.cleaned_data
url = cd.get("url")
url = Extractor.clean_url(url)
# we check if the url is known
existing = Event.objects.filter(uuids__contains=[url])
# if it's unknown
if len(existing) == 0:
event = None
# we import it
logger.warning('on url2event')
u2e = URL2Events(ChromiumHeadlessDownloader(), single_event=True)
events_structure = u2e.process(
url, published=request.user.is_authenticated
)
if (
events_structure is not None
and "events" in events_structure
and len(events_structure["events"]) > 0
):
event = Event.from_structure(
events_structure["events"][0],
events_structure["header"]["url"],
)
# add a category if the user selected one
if event.category is None or event.category == Category.get_default_category():
if cd.get("category") is not None:
event.category = cd.get("category")
# TODO: use celery to import the other events
if event is not None:
event.save()
form = EventForm(
instance=event,
is_authenticated=request.user.is_authenticated,
)
messages.success(
request,
_(
"The event has been successfully extracted, and you can now modify it if necessary."
),
)
return render(
request,
"agenda_culturel/event_form.html",
context={"form": form, "from_import": True},
)
else:
form = EventForm(
initial={"reference_urls": [url]},
is_authenticated=request.user.is_authenticated,
)
messages.error(
request,
_(
"Unable to extract an event from the proposed URL. Please use the form below to submit the event."
),
)
return render(
request,
"agenda_culturel/import.html",
context={"form": form, "form_event": form_event},
)
else: else:
published = [ self.event = None
e for e in existing if e.status == Event.STATUS.PUBLISHED
]
drafts = [e for e in existing if e.status == Event.STATUS.DRAFT]
trash = [e for e in existing if e.status == Event.STATUS.TRASH]
if request.user.is_authenticated or len(published) > 1: def exists(self):
event = published[0] if len(published) > 1 else existing[0] return self.url is not None
def is_new(self):
return self.exists() and self.existing is None
def is_event_visible(self):
if not self.is_new():
return False
return self.event is not None
def get_event(self):
if self.event is None:
return None
else:
return self.event
def get_link(self):
e = self.get_event()
if e is None:
return ""
else:
return '<a href="' + e.get_absolute_url() + '">' + escape(e.title) + '</a>'
def to_list(self):
if self.is_new():
return (self.url, self.cat)
def import_from_urls(request):
URLSubmissionFormSet = formset_factory(URLSubmissionForm, extra=10, min_num=1)
if request.method == "POST":
formset = URLSubmissionFormSet(request.POST, request.FILES)
if formset.is_valid():
# evaluate all the forms
ucat = [URLEventEvaluation(form, request.user.is_authenticated) for form in formset.forms]
# for each not new, add a message
for uc in ucat:
if uc.exists() and not uc.is_new():
if uc.is_event_visible():
messages.info( messages.info(
request, request,
_( _('{} has not been submitted since it''s already known: {}.').format(uc.url).format(uc.get_link())
"This URL has already been submitted, and you can find the event below."
),
) )
return HttpResponseRedirect(event.get_absolute_url())
else: else:
if len(drafts) > 0: messages.info(
messages.info( request,
request, _('{} has not been submitted since it''s already known and currently into moderation process.').format(uc.url)
_( )
"This URL has already been submitted and is awaiting moderation."
),
)
elif len(trash) > 0:
messages.info(
request,
_(
"This URL has already been submitted, but has not been selected for publication by the moderation team."
),
)
return render( # keep only new ones
request, ucat = [uc.to_list() for uc in ucat if uc.is_new()]
"agenda_culturel/import.html",
context={"form": form, "form_event": form_event}, # finally process them or go back to home page
) if len(ucat) > 0:
logger.warning(ucat)
messages.info(
request,
_('Integrating {} url(s) into our import process.').format(len(ucat))
)
import_events_from_urls.delay(ucat)
return HttpResponseRedirect(reverse("thank_you"))
else:
return HttpResponseRedirect(reverse("home"))
else:
formset = URLSubmissionFormSet()
return render(request, "agenda_culturel/import_set.html", context={"formset": formset})
def import_from_url(request):
form = URLSubmissionForm()
initial = {
"start_day": date.today() + timedelta(days=1),
"start_time": "20:00",
"end_time": "22:00",
}
form_event = EventForm(initial=initial)
# if the form has been sent
if request.method == "POST":
form = URLSubmissionForm(request.POST)
# if the form is valid
if form.is_valid():
uc = URLEventEvaluation(form, request.user.is_authenticated)
if uc.exists() and not uc.is_new():
if uc.is_event_visible():
messages.info(
request,
_('{} has not been submitted since it''s already known: {}.').format(uc.url).format(uc.get_link())
)
return HttpResponseRedirect(uc.get_event().get_absolute_url())
else:
messages.info(
request,
_('{} has not been submitted since it''s already known and currently into moderation process.').format(uc.url)
)
return HttpResponseRedirect(reverse("home"))
else:
messages.info(
request,
_('Integrating {} into our import process.').format(uc.url)
)
import_events_from_urls.delay([uc.to_list()])
return HttpResponseRedirect(reverse("thank_you"))
return render(
request,
"agenda_culturel/import.html",
context={"form": form, "form_event": form_event},
)
def export_event_ical(request, year, month, day, pk): def export_event_ical(request, year, month, day, pk):