ShowManager.vue 45 KB
Newer Older
1
<template>
2
  <b-container>
3
4
    <!-- This first row is so far only used to provide a dropdown for
    choosing one of the loaded shows (which the user has access to) -->
5
    <b-row>
6
7
8
      <b-col>
        <h3>Sendungen verwalten</h3>
      </b-col>
9
      <b-col align="right">
10
11
12
        <b-button
          v-if="$parent.user.steeringUser.is_superuser"
          v-b-popover.hover.top="'Add a new show'"
13
          variant="info"
14
15
16
17
18
          @click="$refs.appModalSuperuser.showModalAddShow()"
        >
          +
        </b-button>
        &nbsp;
19
20
21
        <b-dropdown
          id="ddshows"
          text="Sendereihe auswählen"
22
          variant="outline-info"
23
24
        >
          <b-dropdown-item
25
            v-for="(show, index) in shows"
26
27
28
29
30
            :key="show.id"
            @click="switchShow(index)"
          >
            {{ show.name }}
          </b-dropdown-item>
31
32
33
        </b-dropdown>
      </b-col>
    </b-row>
34
    <hr>
35

36
37
    <!-- The jumbotron is used to display the name and description of the
    currently selected show -->
38
    <b-jumbotron>
39
      <!-- The show title goes into the jumbotron header -->
40
      <template slot="header">
41
42
        <span v-if="loaded.shows">
          {{ shows[currentShow].name }}
43
44
45
46
47
          <img
            src="../assets/16x16/emblem-system.png"
            alt="edit name of show"
            @click="$refs.appModalShow.showName()"
          >
48
        </span>
49
50
        <span v-else>Shows are being loaded</span>
      </template>
51
      <!-- The short description of the show goes into the jumbotron lead -->
52
      <template slot="lead">
53
        <span v-if="loaded.shows">{{ shows[currentShow].short_description }}</span>
54
55
56
57
58
        <img
          src="../assets/16x16/emblem-system.png"
          alt="edit short description"
          @click="$refs.appModalShow.showShortDescription()"
        >
59
      </template>
60
      <!-- The rest of the jumbotron is filled with the show description -->
61
      <div v-if="loaded.shows">
62
63
64
65
66
        <b>Description:</b> <img
          src="../assets/16x16/emblem-system.png"
          alt="edit description"
          @click="$refs.appModalShow.showDescription()"
        >
67
        <div>
68
69
70
71
72
73
          <!--
          we are disabling the linter warning for the next line, because, while it
          generally is not advisible to use v-html, in this case we took thorough
          steps to sanitize the date before inserting it into the DOM
          -->
          <!-- eslint-disable-next-line vue/no-v-html -->
74
          <p v-html="sanitizedShowDescription" />
75
76
          <!-- TODO: add image and logo here? -->
        </div>
77

78
        <div
79
          v-if="$parent.user.steeringUser.is_superuser"
80
          align="center"
81
        >
82
83
84
85
          <div v-if="shows[currentShow].is_active">
            <b-button
              variant="danger"
              size="sm"
86
              @click="$refs.appModalSuperuser.showModalDeactivateShow(shows[currentShow])"
87
88
89
90
91
92
93
94
95
96
97
98
99
            >
              Deactivate show
            </b-button>
          </div>
          <div v-else>
            <b-alert
              variant="danger"
              show
            >
              This show is currently not active!<br><br>
              <b-button
                variant="success"
                size="sm"
100
                @click="$refs.appModalSuperuser.activateShow(shows[currentShow])"
101
102
103
104
105
106
              >
                Activate!
              </b-button>
            </b-alert>
          </div>
        </div>
107
      </div>
108
109
    </b-jumbotron>

110
    <!-- If the shows are not fully loaded yet, we just put the loading sign -->
111
    <div v-if="!loaded.shows">
112
113
      <b-row>
        <b-col align="center">
114
115
116
117
          <img
            src="../assets/radio.gif"
            alt="loading data"
          >
118
119
        </b-col>
      </b-row>
120
    </div>
121
122

    <!-- When all show data is loaded, here we display all the rest -->
123
    <div v-else>
124
      <!-- include the modals to edit show and timeslot entries from the modal compontents -->
125
126
127
128
129
130
131
132
133
      <app-modalShow
        ref="appModalShow"
        :show="shows[currentShow]"
      />
      <app-modalNotes
        ref="appModalNotes"
        :show="shows[currentShow]"
        :show-aggregate="current"
      />
134
135
136
      <app-modalSuperuser
        ref="appModalSuperuser"
      />
137
138
139
      <app-modalPlaylist
        ref="appModalPlaylist"
      />
140

141
      <!-- here are the filter settings for our timeslots table -->
142
      <b-card>
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
        <b-row>
          <b-col>
            <b-btn v-b-toggle.timeslotFilterCollapse>
              Toggle timeslot filters
            </b-btn>
          </b-col>
          <b-col align="right">
            <b-button
              v-if="$parent.user.steeringUser.is_superuser"
              variant="info"
              @click="$router.push({path: 'emissions', query: { show: currentShow }})"
            >
              Switch to Emission Manager
            </b-button>
          </b-col>
        </b-row>

160
        <b-collapse id="timeslotFilterCollapse">
161
          <br>
162
          <!-- How many slots to show per table page -->
163
          <b-row>
164
165
166
167
168
169
170
171
172
173
            <b-col sm="3">
              <label for="inputNumSlots">Number of slots to show:</label>
            </b-col>
            <b-col sm="9">
              <b-form-input
                id="inputNumSlots"
                v-model="numSlots"
                type="number"
              />
            </b-col>
174
          </b-row>
175
          <!-- The start date to display timeslots from (defaults to today) -->
176
          <b-row>
177
178
179
180
181
182
183
184
185
186
            <b-col sm="3">
              <label for="inputDateStart">From:</label>
            </b-col>
            <b-col sm="9">
              <b-form-input
                id="inputDateStart"
                v-model="dateStart"
                type="date"
              />
            </b-col>
187
          </b-row>
188
          <!-- The end date until to wich to display timeslots -->
189
          <b-row>
190
191
192
193
194
195
196
197
198
199
            <b-col sm="3">
              <label for="inputNumSlots">Until (exclusive):</label>
            </b-col>
            <b-col sm="9">
              <b-form-input
                id="inputDateEnd"
                v-model="dateEnd"
                type="date"
              />
            </b-col>
200
          </b-row>
201
          <br>
202
          <!-- And finally two buttons, one to reset and one to apply the filter -->
203
204
205
206
207
208
209
210
211
212
213
          <b-container
            fluid
            class="text-right"
          >
            <b-btn
              variant="outline-danger"
              @click="resetFilter()"
            >
              Reset filter
            </b-btn> &nbsp;
            <b-btn
214
              variant="outline-success"
215
216
217
218
              @click="applyFilter()"
            >
              Apply filter
            </b-btn>
219
220
221
222
          </b-container>
        </b-collapse>
      </b-card>

223
      <br>
224

225
226
      <!-- here we show our table of timeslots, if the timeslots are already
      loaded (otherwise we just show the loading symbol) -->
227
      <div v-if="loaded.timeslots">
228
229
230
231
232
233
234
        <b-table
          striped
          hover
          outlined
          :fields="notesTableArrayFields"
          :items="notesTableArray"
        >
235
          <!-- Title of the timeslot (if already set) -->
236
          <template v-slot:cell(title)="data">
237
238
239
            <span v-if="data.value">{{ data.value }}</span>
            <span v-else><small><i>(none set)</i></small></span>
          </template>
240
          <!-- Date and time when this timeslot starts -->
241
          <template v-slot:cell(starts)="data">
242
243
            {{ data.value }}
          </template>
244
          <!-- The duration of this timeslot -->
245
          <template v-slot:cell(duration)="data">
246
247
            {{ data.value }}
          </template>
248
249
          <!-- And here all the buttons for editing and doing other things
          with the displayed timeslot -->
250
          <template v-slot:cell(options)="data">
251
252
253
254
255
256
257
258
259
260
            <span
              class="timeslotEditLink"
              @click="editTimeslotNote(data.item.options.id, data.item.options.schedule)"
            ><img
              src="../assets/16x16/emblem-system.png"
              alt="Edit description"
              title="Edit description"
            ></span>
            <span
              class="timeslotEditLink"
261
              @click="editTimeslotPlaylist(shows[currentShow], data.item.options.schedule, data.item.options.id)"
262
263
            ><img
              src="../assets/16x16/media-eject.png"
264
265
              alt="Edit playlist"
              title="Edit playlist"
266
267
            ></span>
            <span
268
              v-if="data.item.options.play"
269
270
271
272
              class="timeslotEditLink"
              @click="notYetImplemented()"
            ><img
              src="../assets/16x16/media-playback-start.png"
273
274
              alt="Open player"
              title="Open player"
275
            ></span>
276
277
278
279
280
          </template>

          <template v-slot:cell(playlist)="data">
            <span v-if="data.value">{{ data.value }}</span>
            <span v-else><small><i>(none set)</i></small></span>
281
282
          </template>
        </b-table>
283
284
285
286
287
288
289
290
        <b-pagination
          v-model="current.timeslotmeta.page"
          align="center"
          :total-rows="current.timeslotmeta.count"
          :per-page="current.timeslotmeta.perpage"
          @change="timeslotsPage"
        />
      </div>
291
292
293
294
295
296
297
298
299
      <!-- If the timeslot data is not loaded, we just show the spinner instead
      of the table itself -->
      <div v-else>
        <div style="text-align: center;">
          <img
            src="../assets/radio.gif"
            alt="loading data"
          ><br>
        </div>
300
301
      </div>

302
      <hr>
303

304
      <h2>Allgemeine Einstellungen zur Sendereihe:</h2>
305

306
307
308
      <b-row>
        <b-col lg="6">
          <p>
309
310
311
            <b-badge variant="light">
              E-Mail:
            </b-badge>
312
313
            <span v-if="shows[currentShow].email === null"><small><i>(none set)</i></small></span>
            <span v-else>{{ shows[currentShow].email }}</span>
314
315
316
317
318
            <img
              src="../assets/16x16/emblem-system.png"
              alt="edit contact e-mail"
              @click="$refs.appModalShow.showEmail()"
            >
319
320
          </p>
        </b-col>
321

322
323
        <b-col lg="6">
          <p>
324
325
326
            <b-badge variant="light">
              Website:
            </b-badge>
327
328
            <span v-if="shows[currentShow].website === null"><small><i>(none set)</i></small></span>
            <span v-else><a :href="shows[currentShow].website">{{ shows[currentShow].website }}</a></span>
329
330
331
332
333
            <img
              src="../assets/16x16/emblem-system.png"
              alt="edit website"
              @click="$refs.appModalShow.showWebsite()"
            >
334
335
          </p>
        </b-col>
336

337
338
        <b-col lg="6">
          <p>
339
340
341
            <b-badge variant="light">
              Show type:
            </b-badge>
342
343
344
345
            <!-- TODO: discuss: should this be visible to show owners or only to administrators? -->
            <span v-if="loaded.type">
              <span v-if="current.type.length === 0"><small><i>(none set)</i></small></span>
              <span v-else>{{ current.type[0].type }}</span>
346
347
348
349
350
              <img
                src="../assets/16x16/emblem-system.png"
                alt="edit"
                @click="$refs.appModalShow.showType()"
              >
351
            </span>
352
353
354
355
356
            <span v-else><img
              src="../assets/radio.gif"
              height="24px"
              alt="loading data"
            ></span>
357
358
          </p>
        </b-col>
359

360
361
        <b-col lg="6">
          <p>
362
363
364
            <b-badge variant="light">
              Funding category (eg. for RTR):
            </b-badge>
365
            <!-- TODO: discuss: should this be visible to show owners or only to administrators? -->
366
367
368
            <span v-if="loaded.fundingcategory">
              <span v-if="current.fundingcategory.length === 0"><small><i>(none set)</i></small></span>
              <span v-else>{{ current.fundingcategory[0].fundingcategory }}</span>
369
370
371
372
373
              <img
                src="../assets/16x16/emblem-system.png"
                alt="edit"
                @click="$refs.appModalShow.showFundingCategory()"
              >
374
            </span>
375
376
377
378
379
            <span v-else><img
              src="../assets/radio.gif"
              height="24px"
              alt="loading data"
            ></span>
380
381
          </p>
        </b-col>
382

383
384
385
        <b-col lg="6">
          <p>
            <!-- TODO: discuss: should this be visible to show owners or only to administrators? -->
386
            <!-- TODO: fetch name for predecessor from steering api -->
387
388
389
            <b-badge variant="light">
              Predecessor:
            </b-badge>
390
            <span v-if="shows[currentShow].predecessor === null"><small><i>This show has no predecessor show.</i></small></span>
391
            <span v-else>{{ predecessorName }}</span>
392
393
394
395
396
            <img
              src="../assets/16x16/emblem-system.png"
              alt="edit"
              @click="$refs.appModalShow.showPredecessor()"
            >
397
398
          </p>
        </b-col>
399

400
401
        <b-col lg="6">
          <p>
402
403
404
            <b-badge variant="light">
              CBA Series ID:
            </b-badge>
405
406
            <span v-if="shows[currentShow].cba_series_id === null"><small><i>(none set)</i></small></span>
            <span v-else>{{ shows[currentShow].cba_series_id }}</span>
407
408
409
410
411
            <img
              src="../assets/16x16/emblem-system.png"
              alt="edit CBA series ID"
              @click="$refs.appModalShow.showCBAid()"
            >
412
413
          </p>
        </b-col>
414

415
416
        <b-col lg="6">
          <p>
417
418
419
            <b-badge variant="light">
              Fallback List/Pool:
            </b-badge>
420
421
            <span v-if="shows[currentShow].fallback_id === ''"><small><i>(none set)</i></small></span>
            <span v-else>ID: {{ shows[currentShow].fallback_id }}</span>
422
423
424
425
426
            <img
              src="../assets/16x16/emblem-system.png"
              alt="edit"
              @click="notYetImplemented"
            >
427
428
429
          </p>
        </b-col>
      </b-row>
430

431
432
433
434
435
436
437
438
439
440
441
      <hr v-if="$parent.user.steeringUser.is_superuser">
      <b-row v-if="$parent.user.steeringUser.is_superuser">
        <b-col lg="2">
          <b-badge
            variant="info"
            style="width:80%;"
          >
            Owners:
          </b-badge> <img
            src="../assets/16x16/emblem-system.png"
            alt="edit"
442
            @click="$refs.appModalSuperuser.showModalOwners(shows[currentShow])"
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
          >
        </b-col>
        <b-col lg="10">
          <div v-if="loaded.owners">
            <p v-if="shows[currentShow].owners.length === 0">
              <small><i>(none set)</i></small>
            </p>
            <p v-else>
              <!-- TODO: make link on name; when user clicks, open modal to edit host -->
              <ul>
                <li
                  v-for="owner in current.owners"
                  :key="owner.id"
                >
                  {{ owner.first_name }} {{ owner.last_name }}
                  <b-badge variant="light">
                    username:
                  </b-badge> <small>{{ owner.username }}</small>
                  <span v-if="owner.email.length > 0">
                    <b-badge variant="light">
                      email:
                    </b-badge> <small>{{ owner.email }}</small>
                  </span>
                </li>
              </ul>
            </p>
          </div>
          <div v-else>
            <img
              src="../assets/radio.gif"
              height="24px"
              alt="loading data"
            ><br>
          </div>
        </b-col>
      </b-row>
      <hr v-if="$parent.user.steeringUser.is_superuser">

481
482
      <b-row>
        <b-col lg="2">
483
484
485
486
487
488
489
          <b-badge style="width:80%;">
            Categories:
          </b-badge> <img
            src="../assets/16x16/emblem-system.png"
            alt="edit"
            @click="$refs.appModalShow.showCategories()"
          >
490
491
492
493
494
495
496
497
        </b-col>
        <b-col lg="4">
          <div v-if="loaded.categories">
            <p v-if="shows[currentShow].category.length === 0">
              <small><i>(none set)</i></small>
            </p>
            <p v-else>
              <ul>
498
499
500
501
502
503
                <li
                  v-for="cat in current.categories"
                  :key="cat.id"
                >
                  {{ cat.category }}
                </li>
504
505
506
              </ul>
            </p>
          </div>
507
508
509
510
511
512
513
          <div v-else>
            <img
              src="../assets/radio.gif"
              height="24px"
              alt="loading data"
            ><br>
          </div>
514
        </b-col>
515

516
        <b-col lg="2">
517
518
519
520
521
522
523
          <b-badge style="width:80%;">
            Topics:
          </b-badge> <img
            src="../assets/16x16/emblem-system.png"
            alt="edit"
            @click="$refs.appModalShow.showTopics()"
          >
524
525
526
527
528
529
530
531
        </b-col>
        <b-col lg="4">
          <div v-if="loaded.topics">
            <p v-if="shows[currentShow].topic.length === 0">
              <small><i>(none set)</i></small>
            </p>
            <p v-else>
              <ul>
532
533
534
535
536
537
                <li
                  v-for="topic in current.topics"
                  :key="topic.id"
                >
                  {{ topic.topic }}
                </li>
538
539
540
              </ul>
            </p>
          </div>
541
542
543
544
545
546
547
          <div v-else>
            <img
              src="../assets/radio.gif"
              height="24px"
              alt="loading data"
            ><br>
          </div>
548
        </b-col>
549

550
        <b-col lg="2">
551
552
553
554
555
556
557
          <b-badge style="width:80%;">
            Musicfocus:
          </b-badge> <img
            src="../assets/16x16/emblem-system.png"
            alt="edit"
            @click="$refs.appModalShow.showMusicFocus()"
          >
558
559
560
561
562
563
564
565
        </b-col>
        <b-col lg="4">
          <div v-if="loaded.musicfocus">
            <p v-if="shows[currentShow].musicfocus.length === 0">
              <small><i>(none set)</i></small>
            </p>
            <p v-else>
              <ul>
566
567
568
569
570
571
                <li
                  v-for="focus in current.musicfocus"
                  :key="focus.id"
                >
                  {{ focus.focus }}
                </li>
572
573
574
              </ul>
            </p>
          </div>
575
576
577
578
579
580
581
          <div v-else>
            <img
              src="../assets/radio.gif"
              height="24px"
              alt="loading data"
            ><br>
          </div>
582
        </b-col>
583

584
        <b-col lg="2">
585
586
587
588
589
590
591
          <b-badge style="width:80%;">
            Languages:
          </b-badge> <img
            src="../assets/16x16/emblem-system.png"
            alt="edit"
            @click="$refs.appModalShow.showLanguages()"
          >
592
593
594
595
596
597
598
599
        </b-col>
        <b-col lg="4">
          <div v-if="loaded.languages">
            <p v-if="shows[currentShow].language.length === 0">
              <small><i>(none set)</i></small>
            </p>
            <p v-else>
              <ul>
600
601
602
603
604
605
                <li
                  v-for="lang in current.languages"
                  :key="lang.id"
                >
                  {{ lang.name }}
                </li>
606
607
608
              </ul>
            </p>
          </div>
609
610
611
612
613
614
615
          <div v-else>
            <img
              src="../assets/radio.gif"
              height="24px"
              alt="loading data"
            ><br>
          </div>
616
        </b-col>
617

618
        <b-col lg="2">
619
620
621
622
623
624
625
          <b-badge style="width:80%;">
            Hosts:
          </b-badge> <img
            src="../assets/16x16/emblem-system.png"
            alt="edit"
            @click="$refs.appModalShow.showHosts()"
          >
626
627
628
629
630
631
632
633
634
        </b-col>
        <b-col lg="4">
          <div v-if="loaded.hosts">
            <p v-if="shows[currentShow].hosts.length === 0">
              <small><i>(none set)</i></small>
            </p>
            <p v-else>
              <!-- TODO: make link on name; when user clicks, open modal to edit host -->
              <ul>
635
636
637
638
639
640
                <li
                  v-for="host in current.hosts"
                  :key="host.id"
                >
                  {{ host.name }}
                </li>
641
642
643
              </ul>
            </p>
          </div>
644
645
646
647
648
649
650
          <div v-else>
            <img
              src="../assets/radio.gif"
              height="24px"
              alt="loading data"
            ><br>
          </div>
651
652
        </b-col>
      </b-row>
653
654
655

      <b-row>
        <b-col lg="2">
656
657
658
659
660
661
662
          <b-badge style="width:80%;">
            Logo:
          </b-badge> <img
            src="../assets/16x16/emblem-system.png"
            alt="edit"
            @click="$refs.appModalShow.showLogo()"
          >
663
664
        </b-col>
        <b-col lg="4">
665
          <div v-if="current.logo.length === 0">
666
667
668
            <small><i>(none set)</i></small>
          </div>
          <div v-else>
669
670
671
672
673
674
675
            <br>
            <b-img
              thumbnail
              :src="current.logo"
              fluid
              @click="$refs.appModalShow.showLogo()"
            />
676
677
678
679
          </div>
        </b-col>

        <b-col lg="2">
680
681
682
683
684
685
686
          <b-badge style="width:80%;">
            Image:
          </b-badge> <img
            src="../assets/16x16/emblem-system.png"
            alt="edit"
            @click="$refs.appModalShow.showImage()"
          >
687
688
        </b-col>
        <b-col lg="4">
689
          <div v-if="current.image.length === 0">
690
691
692
            <small><i>(none set)</i></small>
          </div>
          <div v-else>
693
694
695
696
697
698
699
            <br>
            <b-img
              thumbnail
              :src="current.image"
              fluid
              @click="$refs.appModalShow.showImage()"
            />
700
701
702
703
          </div>
        </b-col>
      </b-row>

704
      <hr>
705
    </div>
706
  </b-container>
707
708
709
</template>

<script>
710
import modalNotes from './ShowManagerModalNotes.vue'
711
import modalShow from './ShowManagerModalShow.vue'
712
import modalSuperuser from './ShowManagerModalSuperuser.vue'
713
import modalPlaylist from './ShowManagerModalPlaylist.vue'
714
import timeslotSort from '../mixins/timeslotSort'
715
import prettyDate from '../mixins/prettyDate'
716
import axios from 'axios'
717
import DOMPurify from 'dompurify'
718
719

export default {
720
721
  // all modals to edit a show and its timeslots/notes, are importet as separate
  // components, to make it a tiny lickle bit less messy here
722
  components: {
723
    'app-modalNotes': modalNotes,
724
725
    'app-modalShow': modalShow,
    'app-modalSuperuser': modalSuperuser,
726
    'app-modalPlaylist': modalPlaylist,
727
  },
728
729

  // generic functions that we want to use from our mixins folder
730
  mixins: [ timeslotSort, prettyDate ],
731
732
733

  // this component will be handling a lot of data - probably the component can
  // be refactored to get rid of some redundancy here
734
735
  data () {
    return {
736
737
738
      shows: [],      // an array of objects describing our shows (empty at load, will be populated on created())
      currentShow: 0,   // index of the currently selected show in our shows array
      currentShowID: 0, // actual id of the currently selected show
739
      numSlots: process.env.VUE_APP_TIMESLOT_FILTER_DEFAULT_NUMSLOTS, // all form input values are provided as strings
740
      dateStart: this.apiDate(new Date()),
741
      dateEnd: this.apiDate(new Date(new Date().getTime() + process.env.VUE_APP_TIMESLOT_FILTER_DEFAULT_DAYS * 86400000)),
742
743
744

      // the loaded object holds flags for the different things we will fetch
      // from the AuRa steering module
745
746
747
748
749
750
751
752
753
      loaded: {
        shows: false,
        timeslots: false,
        notes: false,
        categories: false,
        hosts: false,
        languages: false,
        topics: false,
        musicfocus: false,
754
        fundingcategory: false,
755
756
        type: false,
        owners: false,
757
        playlists: false,
758
      },
759
760
761

      // the current object is used to hold all the necessary data to describe
      // the show which is currently selected by the user in the frontend
762
763
764
765
766
767
      current: {
        categories: [],
        hosts: [],
        languages: [],
        topics: [],
        musicfocus: [],
768
        fundingcategory: [],
769
        type: [],
770
        playlists: [],
771
772
773
774
        timeslots: [],
        timeslotmeta: {    // meta info when pagination is used
          count: 0,
          next: null,
775
776
777
          previous: null,
          page: 1,   // page indexes start at 1 for <b-pagination> components
          perpage: 10
778
779
        },
        note: {},
780
781
        notes: [],
        image: '',
782
783
        logo: '',
        owners: [],
784
      },
785
786

      // this is used to configure the table with all the filtered timeslots
787
788
789
790
      notesTableArrayFields: [
        { key: 'title', label: 'Title of emission' },
        { key: 'starts', label: 'Emission start' },
        { key: 'duration', label: 'Duration' },
791
792
        { key: 'options', label: 'Edit' },
        { key: 'playlist', label: 'Playlist' },
793
      ]
794
795
    }
  },
796

jackie / Andrea Ida Malkah Klaura's avatar
jackie / Andrea Ida Malkah Klaura committed
797
  // Some of the info we need in the template are not easily and directly
798
  // retrievable, so we are computing them on the fly, when they are needed
799
  computed: {
800
801
802
803
804

    // As the show description should allow to be html-formatted, we have to
    // make sure no malicous code can be inserted into the DOM. For that the
    // DOMPurify library (https://github.com/cure53/DOMPurify) does us a much
    // better service than trying to sanitize it with some RegExp.
805
806
807
    sanitizedShowDescription: function () {
      return DOMPurify.sanitize(this.shows[this.currentShow].description)
    },
808
809
810
811
812
813
814
815

    // In order to not only just show the predecessor of a show as an ID. we
    // have to find it in our shows array to then output the predecessors name.
    // This currently assumes that a user has access to all the predecessors
    // of the shows as well.
    // TODO/discuss: if all predecessor names should be accessible, independent
    // of access rights, then we would need to load all predecessors show after
    // loading our initial shows as well.
816
817
    predecessorName: function () {
      for (var i in this.shows) {
818
        if (this.shows[i].id === this.shows[this.currentShow].predecessor) {
819
820
821
822
823
          return this.shows[i].name
        }
      }
      return 'Name of predecessor show not available'
    },
824
825
826

    // As we do not have a single object which holds all info we need to display
    // in the table with our timeslots, we use this computed array to do that
827
    notesTableArray: function () {
828
      let rows = []
829
      for (var i in this.current.timeslots) {
830
        let note = this.getNoteByTimeslotID(this.current.timeslots[i].id)
831
        if (note !== null) { note = note.title }
832
833
834
835

        let playlistTitle = ''
        if (this.current.timeslots[i].playlist_id !== null) {
          let playlist = this.current.playlists.find(list => list.id === this.current.timeslots[i].playlist_id)
836
837
838
839
840
841
          if (playlist) {
            if (playlist.description.length > 0) {
              playlistTitle = playlist.description
            } else {
              playlistTitle = playlist.id
            }
842
843
844
845
          }
        }

        rows.push({
846
847
          title: note,
          starts: this.prettyDateTime(this.current.timeslots[i].start),
848
          duration: this.prettyDuration(this.current.timeslots[i].start, this.current.timeslots[i].end),
849
850
          options: {
            id: this.current.timeslots[i].id,
851
852
853
854
            schedule: this.current.timeslots[i].schedule,
            play: this.current.timeslots[i].playlist_id !== null
          },
          playlist: playlistTitle
855
856
        })
      }
857
      return rows
858
859
    }
  },
860
861
862

  // Right after this component is set up, we want to fetch all available shows
  // from the AuRa steering module.
863
  created () {
864
865
866
    // As we don't know any shows yet, we use null as id parameter, so the
    // first show in the returned show array will be displayed
    this.loadAndSwitch(null)
867
  },
868
869
870

  // Now for our hotchpotch of methods, mostly used for fetching data from the
  // AuRa steering API (updateing will be done in the imported modal components)
871
  methods: {
872
873

    // Apply the newly set filter parameters for our timeslot table
874
875
876
877
    applyFilter: function () {
      this.current.timeslotmeta.page = 1
      this.getTimeslots(this.dateStart, this.dateEnd, this.numSlots)
    },
878
879

    // Reset the filter parameters for our timeslot table to config defaults
880
    resetFilter: function () {
881
      this.numSlots = process.env.VUE_APP_TIMESLOT_FILTER_DEFAULT_NUMSLOTS
882
      this.dateStart = this.apiDate(new Date())
883
      this.dateEnd = this.apiDate(new Date(new Date().getTime() + process.env.VUE_APP_TIMESLOT_FILTER_DEFAULT_DAYS * 86400000))
884
885
886
      this.current.timeslotmeta.page = 1
      this.getTimeslots(this.dateStart, this.dateEnd, this.numSlots)
    },
887
888

    // Load a different page of timeslots for the timeslots table
889
890
891
892
893
894
    timeslotsPage: function (page) {
      if (this.current.timeslotmeta.page !== page) {
        this.current.timeslotmeta.page = page
        this.getTimeslots(this.dateStart, this.dateEnd, this.numSlots, (page - 1) * this.numSlots)
      }
    },
895
896
897
898
899
900
901
902

    // Every time the user switches to another show, we will load all related
    // data (as e.g. categories, hosts, etc.) from the AuRa steering API, in case
    // something changed.
    // TODO/discuss: maybe this is too inefficient and we could only load this
    // data just in the beginning after shows are loaded and assume they do not
    // change throughout a session or put it into the user's responsibility to
    // reload the show manager page after relevant changes.
903
    switchShow: function (index) {
904
905
906
      // if we already had some show loaded with timeslots and notes, set these to
      // not loaded, so we don't display old timeslots and notes while already
      // the new show is displayed and new timeslots and notes are still loading
907
908
909
910
911
912
913
914
      this.loaded.timeslots = false
      this.loaded.notes = false
      // also for those settings of the show which are only ids or arrays of ids
      // we have to fetch the corresponding names first
      this.loaded.categories = false
      this.loaded.hosts = false
      this.loaded.languages = false
      this.loaded.musicfocus = false
915
      this.loaded.fundingcategory = false
916
      this.loaded.owners = false
917
      // set the current show and its ID to whatever we want to switch to now
918
      this.currentShow = index
919
      this.currentShowID = this.shows[this.currentShow].id
920
921
      // and check if images are available and set image strings, because we
      // cannot use them directly inside the b-img if they are null
922
923
924
925
      if (this.shows[this.currentShow].logo === null) { this.current.logo = '' }
      else { this.current.logo = this.shows[this.currentShow].logo }
      if (this.shows[this.currentShow].image === null) { this.current.image = '' }
      else { this.current.image = this.shows[this.currentShow].image }
926
927
928
929
930
931
      // before we load timeslots and notes, we want to fetch the general settings first
      this.getCategories()
      this.getHosts()
      this.getLanguages()
      this.getTopics()
      this.getMusicfocus()
932
      this.getFundingCategory()
933
      this.getType()
934
935
936
      if (this.$parent.user.steeringUser.is_superuser) {
        this.getOwners()
      }
937
      this.getTimeslots(this.dateStart, this.dateEnd, this.numSlots)
938
      this.loadPlaylists()
939
    },
940

941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
    // (Re)Load all shows from server and switch to a show with a specific ID.
    // If the id argument is null, the first show in the show array will be used
    loadAndSwitch: function (id) {
      this.loaded.shows = false
      var uri = process.env.VUE_APP_API_STEERING_SHOWS
      // normal users should only see their own shows, only superusers see all shows
      if (!this.$parent.user.steeringUser.is_superuser) {
        uri += '?owner=' + this.$parent.user.steeringUser.id
      }
      axios.get(uri, {
        withCredentials: true,
        headers: { 'Authorization': 'Bearer ' + this.$parent.user.access_token }
      }).then(response => {
        // if now shows are found, we'll just print a short info message and leave
        if (response.data.length === 0) {
          this.$log.info('The returned show set has 0 length:')
          this.$log.info(response)
          alert('Info: There are no shows connected to your account. See console for details.')
          this.loaded.shows = true
          return
        }
        // now set the new show array and find the index of the show ID
        this.shows = response.data
        let index = 0
        if (id !== null) {
          index = this.shows.findIndex(show => show.id === id)
          // if no show with the given ID was found, we use the first item in the show array
          if (index === -1) { index = 0 }
        }
        this.currentShow = index
        this.currentShowID = this.shows[index].id
        this.loaded.shows = true
        this.switchShow(this.currentShow)
      }).catch(error => {
        this.$log.error(error.response.status + ' ' + error.response.statusText)
        this.$log.error(error.response)
        alert('Error: could not fetch show data. See console for details.')
      })
    },

981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
    loadPlaylists () {
      this.loaded.playlists = false
      let uri = process.env.VUE_APP_API_TANK + 'shows/' + this.shows[this.currentShow].slug + '/playlists'
      axios.get(uri, {
        withCredentials: true,
        headers: { 'Authorization': 'Bearer ' + this.$parent.user.access_token }
      }).then(response => {
        // we don't have to check separately, if there are playlists, because tank
        // always provides an empty array if there are no playlists (or even if there is no corresponding show)
        this.current.playlists = response.data.results
        this.loaded.playlists = true
      }).catch(error => {
        //this.$log.error(error.response.status + ' ' + error.response.statusText)
        //this.$log.error(error.response)
        this.$log.error(error)
        alert('Error: could not fetch playlists from tank. See console for details.')
      })
    },

1000
    // Fetch timeslots for the current show and use filter variables if provided