Initial commit
302
00-pflichtenheft/.gitignore
vendored
Normal file
|
@ -0,0 +1,302 @@
|
|||
## Core latex/pdflatex auxiliary files:
|
||||
*.aux
|
||||
*.lof
|
||||
*.log
|
||||
*.lot
|
||||
*.fls
|
||||
*.out
|
||||
*.toc
|
||||
*.fmt
|
||||
*.fot
|
||||
*.cb
|
||||
*.cb2
|
||||
.*.lb
|
||||
|
||||
## Intermediate documents:
|
||||
*.dvi
|
||||
*.xdv
|
||||
*-converted-to.*
|
||||
# these rules might exclude image files for figures etc.
|
||||
# *.ps
|
||||
# *.eps
|
||||
*.pdf
|
||||
!assets/*.pdf
|
||||
|
||||
## Generated if empty string is given at "Please type another file name for output:"
|
||||
.pdf
|
||||
|
||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||
*.bbl
|
||||
*.bcf
|
||||
*.blg
|
||||
*-blx.aux
|
||||
*-blx.bib
|
||||
*.run.xml
|
||||
|
||||
## Build tool auxiliary files:
|
||||
*.fdb_latexmk
|
||||
*.synctex
|
||||
*.synctex(busy)
|
||||
*.synctex.gz
|
||||
*.synctex.gz(busy)
|
||||
*.pdfsync
|
||||
|
||||
## Build tool directories for auxiliary files
|
||||
# latexrun
|
||||
latex.out/
|
||||
|
||||
## Auxiliary and intermediate files from other packages:
|
||||
# algorithms
|
||||
*.alg
|
||||
*.loa
|
||||
|
||||
# achemso
|
||||
acs-*.bib
|
||||
|
||||
# amsthm
|
||||
*.thm
|
||||
|
||||
# beamer
|
||||
*.nav
|
||||
*.pre
|
||||
*.snm
|
||||
*.vrb
|
||||
|
||||
# changes
|
||||
*.soc
|
||||
|
||||
# comment
|
||||
*.cut
|
||||
|
||||
# cprotect
|
||||
*.cpt
|
||||
|
||||
# elsarticle (documentclass of Elsevier journals)
|
||||
*.spl
|
||||
|
||||
# endnotes
|
||||
*.ent
|
||||
|
||||
# fixme
|
||||
*.lox
|
||||
|
||||
# feynmf/feynmp
|
||||
*.mf
|
||||
*.mp
|
||||
*.t[1-9]
|
||||
*.t[1-9][0-9]
|
||||
*.tfm
|
||||
|
||||
#(r)(e)ledmac/(r)(e)ledpar
|
||||
*.end
|
||||
*.?end
|
||||
*.[1-9]
|
||||
*.[1-9][0-9]
|
||||
*.[1-9][0-9][0-9]
|
||||
*.[1-9]R
|
||||
*.[1-9][0-9]R
|
||||
*.[1-9][0-9][0-9]R
|
||||
*.eledsec[1-9]
|
||||
*.eledsec[1-9]R
|
||||
*.eledsec[1-9][0-9]
|
||||
*.eledsec[1-9][0-9]R
|
||||
*.eledsec[1-9][0-9][0-9]
|
||||
*.eledsec[1-9][0-9][0-9]R
|
||||
|
||||
# glossaries
|
||||
*.acn
|
||||
*.acr
|
||||
*.glg
|
||||
*.glo
|
||||
*.gls
|
||||
*.glsdefs
|
||||
*.lzo
|
||||
*.lzs
|
||||
*.slg
|
||||
*.slo
|
||||
*.sls
|
||||
|
||||
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
||||
*.ist
|
||||
|
||||
# gnuplot
|
||||
*.gnuplot
|
||||
*.table
|
||||
|
||||
# gnuplottex
|
||||
*-gnuplottex-*
|
||||
|
||||
# gregoriotex
|
||||
*.gaux
|
||||
*.glog
|
||||
*.gtex
|
||||
|
||||
# htlatex
|
||||
*.4ct
|
||||
*.4tc
|
||||
*.idv
|
||||
*.lg
|
||||
*.trc
|
||||
*.xref
|
||||
|
||||
# hyperref
|
||||
*.brf
|
||||
|
||||
# knitr
|
||||
*-concordance.tex
|
||||
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
|
||||
# *.tikz
|
||||
*-tikzDictionary
|
||||
|
||||
# listings
|
||||
*.lol
|
||||
|
||||
# luatexja-ruby
|
||||
*.ltjruby
|
||||
|
||||
# makeidx
|
||||
*.idx
|
||||
*.ilg
|
||||
*.ind
|
||||
|
||||
# minitoc
|
||||
*.maf
|
||||
*.mlf
|
||||
*.mlt
|
||||
*.mtc[0-9]*
|
||||
*.slf[0-9]*
|
||||
*.slt[0-9]*
|
||||
*.stc[0-9]*
|
||||
|
||||
# minted
|
||||
_minted*
|
||||
*.pyg
|
||||
|
||||
# morewrites
|
||||
*.mw
|
||||
|
||||
# newpax
|
||||
*.newpax
|
||||
|
||||
# nomencl
|
||||
*.nlg
|
||||
*.nlo
|
||||
*.nls
|
||||
|
||||
# pax
|
||||
*.pax
|
||||
|
||||
# pdfpcnotes
|
||||
*.pdfpc
|
||||
|
||||
# sagetex
|
||||
*.sagetex.sage
|
||||
*.sagetex.py
|
||||
*.sagetex.scmd
|
||||
|
||||
# scrwfile
|
||||
*.wrt
|
||||
|
||||
# svg
|
||||
svg-inkscape/
|
||||
|
||||
# sympy
|
||||
*.sout
|
||||
*.sympy
|
||||
sympy-plots-for-*.tex/
|
||||
|
||||
# pdfcomment
|
||||
*.upa
|
||||
*.upb
|
||||
|
||||
# pythontex
|
||||
*.pytxcode
|
||||
pythontex-files-*/
|
||||
|
||||
# tcolorbox
|
||||
*.listing
|
||||
|
||||
# thmtools
|
||||
*.loe
|
||||
|
||||
# TikZ & PGF
|
||||
*.dpth
|
||||
*.md5
|
||||
*.auxlock
|
||||
|
||||
# titletoc
|
||||
*.ptc
|
||||
|
||||
# todonotes
|
||||
*.tdo
|
||||
|
||||
# vhistory
|
||||
*.hst
|
||||
*.ver
|
||||
|
||||
# easy-todo
|
||||
*.lod
|
||||
|
||||
# xcolor
|
||||
*.xcp
|
||||
|
||||
# xmpincl
|
||||
*.xmpi
|
||||
|
||||
# xindy
|
||||
*.xdy
|
||||
|
||||
# xypic precompiled matrices and outlines
|
||||
*.xyc
|
||||
*.xyd
|
||||
|
||||
# endfloat
|
||||
*.ttt
|
||||
*.fff
|
||||
|
||||
# Latexian
|
||||
TSWLatexianTemp*
|
||||
|
||||
## Editors:
|
||||
# WinEdt
|
||||
*.bak
|
||||
*.sav
|
||||
|
||||
# Texpad
|
||||
.texpadtmp
|
||||
|
||||
# LyX
|
||||
*.lyx~
|
||||
|
||||
# Kile
|
||||
*.backup
|
||||
|
||||
# gummi
|
||||
.*.swp
|
||||
|
||||
# KBibTeX
|
||||
*~[0-9]*
|
||||
|
||||
# TeXnicCenter
|
||||
*.tps
|
||||
|
||||
# auto folder when using emacs and auctex
|
||||
./auto/*
|
||||
*.el
|
||||
|
||||
# expex forward references with \gathertags
|
||||
*-tags.tex
|
||||
|
||||
# standalone packages
|
||||
*.sta
|
||||
|
||||
# Makeindex log files
|
||||
*.lpz
|
||||
|
||||
# xwatermark package
|
||||
*.xwm
|
||||
|
||||
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
|
||||
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
|
||||
# Uncomment the next line to have this generated file ignored.
|
||||
#*Notes.bib
|
15
00-pflichtenheft/.gitlab-ci.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
image: texlive/texlive
|
||||
|
||||
pages:
|
||||
script:
|
||||
- mkdir public
|
||||
- make
|
||||
- mv pflichtenheft.pdf public
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
|
||||
|
||||
|
7
00-pflichtenheft/.latexmkrc
Normal file
|
@ -0,0 +1,7 @@
|
|||
# https://tex.stackexchange.com/questions/1226/how-to-make-latexmk-use-makeglossaries
|
||||
add_cus_dep('glo', 'gls', 0, 'makeglo2gls');
|
||||
add_cus_dep('acn', 'acr', 0, 'makeglo2gls');
|
||||
sub makeglo2gls {
|
||||
system("makeglossaries $_[0]");
|
||||
}
|
||||
|
10
00-pflichtenheft/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
MAIN = pflichtenheft
|
||||
FLAGS = -pdf
|
||||
|
||||
all:
|
||||
latexmk $(FLAGS) $(MAIN)
|
||||
dev:
|
||||
latexmk $(FLAGS) -pvc $(MAIN)
|
||||
clean:
|
||||
latexmk -C
|
||||
|
BIN
00-pflichtenheft/assets/KIT_Deckblatt.pdf
Normal file
BIN
00-pflichtenheft/assets/logo.pdf
Normal file
211
00-pflichtenheft/assets/logo.svg
Normal file
|
@ -0,0 +1,211 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.2"
|
||||
width="87.589989mm"
|
||||
height="52.16547mm"
|
||||
viewBox="0 0 8758.9989 5216.547"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
fill-rule="evenodd"
|
||||
stroke-width="28.222"
|
||||
stroke-linejoin="round"
|
||||
xml:space="preserve"
|
||||
id="svg206"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
class="ClipPathGroup"
|
||||
id="defs8" />
|
||||
<defs
|
||||
id="defs51"><font
|
||||
id="EmbeddedFont_1"
|
||||
horiz-adv-x="2048"
|
||||
horiz-origin-x="0"
|
||||
horiz-origin-y="0"
|
||||
vert-origin-x="512"
|
||||
vert-origin-y="768"
|
||||
vert-adv-y="1024">
|
||||
<font-face
|
||||
font-family="Noto Sans Display Light embedded"
|
||||
units-per-em="2048"
|
||||
font-weight="normal"
|
||||
font-style="normal"
|
||||
ascent="2170"
|
||||
descent="609"
|
||||
id="font-face10" />
|
||||
<missing-glyph
|
||||
horiz-adv-x="2048"
|
||||
d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"
|
||||
id="missing-glyph12" />
|
||||
<glyph
|
||||
unicode="y"
|
||||
horiz-adv-x="927"
|
||||
d="M 2,1089 L 127,1089 367,413 C 388,352 407,298 422,250 437,203 449,161 457,124 L 463,124 C 471,156 483,196 498,246 513,296 530,350 551,409 L 786,1089 913,1089 453,-193 C 418,-290 377,-364 328,-416 279,-468 213,-494 131,-494 107,-494 84,-493 63,-490 43,-487 25,-482 8,-476 L 8,-377 C 23,-383 40,-387 57,-391 75,-394 95,-396 117,-396 170,-396 214,-378 249,-342 284,-307 314,-252 340,-179 L 403,4 2,1089 Z"
|
||||
id="glyph14" />
|
||||
<glyph
|
||||
unicode="t"
|
||||
horiz-adv-x="610"
|
||||
d="M 465,80 C 494,80 521,82 547,87 573,91 595,97 614,105 L 614,11 C 594,3 569,-5 541,-11 512,-17 481,-20 449,-20 363,-20 296,5 249,56 202,106 178,189 178,304 L 178,996 27,996 27,1061 178,1100 219,1350 295,1350 295,1090 608,1090 608,996 295,996 295,310 C 295,157 352,80 465,80 Z"
|
||||
id="glyph16" />
|
||||
<glyph
|
||||
unicode="s"
|
||||
horiz-adv-x="742"
|
||||
d="M 817,289 C 817,191 782,115 713,61 643,7 545,-20 418,-20 347,-20 284,-14 228,-1 173,12 126,29 88,50 L 88,162 C 134,138 186,118 244,102 301,86 360,78 420,78 520,78 592,96 636,133 680,169 702,218 702,281 702,341 679,387 632,419 585,451 515,484 422,519 359,542 303,565 255,589 207,613 169,643 142,680 116,717 102,768 102,832 102,919 136,987 204,1037 271,1086 361,1110 473,1110 535,1110 592,1104 646,1092 700,1080 750,1063 795,1043 L 754,946 C 713,964 667,980 617,993 568,1006 518,1012 469,1012 388,1012 326,997 283,967 239,937 217,893 217,836 217,792 228,758 249,733 270,707 301,686 342,668 383,650 433,630 492,609 553,585 608,562 657,537 707,512 745,481 774,443 803,405 817,353 817,289 Z"
|
||||
id="glyph18" />
|
||||
<glyph
|
||||
unicode="r"
|
||||
horiz-adv-x="583"
|
||||
d="M 596,1108 C 646,1108 692,1102 733,1091 L 717,983 C 674,995 632,1001 590,1001 497,1001 423,964 368,890 312,817 285,719 285,598 L 285,-1 168,-1 168,1089 266,1089 279,886 285,886 C 311,948 350,1000 402,1043 455,1086 520,1108 596,1108 Z"
|
||||
id="glyph20" />
|
||||
<glyph
|
||||
unicode="o"
|
||||
horiz-adv-x="927"
|
||||
d="M 1030,547 C 1030,433 1012,333 976,248 940,164 887,98 818,51 749,4 665,-20 565,-20 471,-20 390,3 322,50 253,96 201,162 164,247 127,333 109,433 109,547 109,723 150,861 232,961 315,1061 429,1110 575,1110 672,1110 755,1087 822,1040 890,993 941,927 977,842 1012,757 1030,659 1030,547 Z M 229,547 C 229,407 257,294 312,208 368,123 453,80 567,80 685,80 771,123 826,209 882,295 909,408 909,547 909,637 898,717 875,787 851,856 815,911 766,951 717,990 653,1010 573,1010 459,1010 373,969 315,887 258,805 229,692 229,547 Z"
|
||||
id="glyph22" />
|
||||
<glyph
|
||||
unicode="n"
|
||||
horiz-adv-x="847"
|
||||
d="M 633,1110 C 749,1110 838,1078 900,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1090 262,1090 279,901 287,901 C 314,962 357,1011 416,1051 474,1091 547,1110 633,1110 Z"
|
||||
id="glyph24" />
|
||||
<glyph
|
||||
unicode="m"
|
||||
horiz-adv-x="1430"
|
||||
d="M 1245,1110 C 1348,1110 1427,1080 1485,1018 1542,957 1571,860 1571,727 L 1571,1 1454,1 1454,723 C 1454,820 1434,892 1393,939 1352,986 1296,1010 1227,1010 1130,1010 1056,980 1005,919 953,858 928,764 928,637 L 928,1 811,1 811,723 C 811,820 791,892 750,939 709,986 653,1010 584,1010 487,1010 413,978 361,914 310,850 285,751 285,619 L 285,1 168,1 168,1090 262,1090 279,918 287,918 C 313,971 352,1016 403,1054 455,1092 521,1110 600,1110 675,1110 739,1093 791,1059 842,1025 879,975 899,908 L 907,908 C 936,972 980,1022 1038,1057 1097,1093 1166,1110 1245,1110 Z"
|
||||
id="glyph26" />
|
||||
<glyph
|
||||
unicode="i"
|
||||
horiz-adv-x="187"
|
||||
d="M 227,1493 C 279,1493 305,1464 305,1405 305,1345 279,1315 227,1315 175,1315 150,1345 150,1405 150,1464 175,1493 227,1493 Z M 285,1090 L 285,0 168,0 168,1090 285,1090 Z"
|
||||
id="glyph28" />
|
||||
<glyph
|
||||
unicode="h"
|
||||
horiz-adv-x="847"
|
||||
d="M 285,1059 C 285,1031 284,1003 283,977 281,951 279,926 276,901 L 285,901 C 312,962 355,1011 413,1051 471,1091 543,1110 629,1110 746,1110 836,1078 899,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1557 285,1557 285,1059 Z"
|
||||
id="glyph30" />
|
||||
<glyph
|
||||
unicode="f"
|
||||
horiz-adv-x="689"
|
||||
d="M 575,995 L 332,995 332,-1 213,-1 213,995 27,995 27,1058 213,1093 213,1202 C 213,1445 316,1566 522,1566 559,1566 593,1563 623,1557 653,1551 680,1544 705,1536 L 678,1439 C 655,1448 630,1454 603,1460 577,1465 550,1468 524,1468 456,1468 407,1447 377,1405 347,1362 332,1295 332,1202 L 332,1089 575,1089 575,995 Z"
|
||||
id="glyph32" />
|
||||
<glyph
|
||||
unicode="e"
|
||||
horiz-adv-x="874"
|
||||
d="M 559,1110 C 646,1110 720,1089 779,1046 839,1003 883,944 913,869 943,794 958,708 958,611 L 958,531 229,531 C 231,386 262,275 325,198 387,121 476,82 592,82 656,82 712,88 759,100 806,111 858,130 915,156 L 915,50 C 865,25 814,7 764,-4 713,-15 655,-20 588,-20 434,-20 315,30 232,129 150,229 109,365 109,537 109,648 126,746 162,832 197,918 249,986 315,1036 382,1085 464,1110 559,1110 Z M 559,1012 C 465,1012 389,979 333,912 276,845 243,750 233,627 L 838,627 C 838,742 815,835 769,906 723,977 653,1012 559,1012 Z"
|
||||
id="glyph34" />
|
||||
<glyph
|
||||
unicode="d"
|
||||
horiz-adv-x="900"
|
||||
d="M 535,-20 C 398,-20 293,27 219,120 145,214 109,352 109,535 109,722 147,865 224,963 301,1061 408,1110 545,1110 629,1110 698,1090 752,1050 805,1010 845,961 872,904 L 881,904 C 879,935 878,970 876,1009 873,1048 872,1084 872,1117 L 872,1557 989,1557 989,0 895,0 879,191 872,191 C 845,132 805,82 751,41 697,0 625,-20 535,-20 Z M 553,80 C 669,80 752,119 801,195 850,271 875,382 875,527 L 875,545 C 875,695 850,810 801,890 752,970 671,1010 559,1010 451,1010 369,969 313,886 257,804 229,686 229,533 229,385 256,273 309,196 363,119 444,80 553,80 Z"
|
||||
id="glyph36" />
|
||||
<glyph
|
||||
unicode="c"
|
||||
horiz-adv-x="768"
|
||||
d="M 580,-20 C 429,-20 313,29 231,127 150,226 109,363 109,539 109,662 129,766 170,850 211,935 269,1000 343,1044 417,1088 504,1110 602,1110 651,1110 698,1106 742,1096 787,1087 825,1074 858,1057 L 825,957 C 791,972 754,984 714,993 673,1002 636,1006 600,1006 481,1006 390,964 326,881 261,798 229,685 229,541 229,405 258,294 314,210 371,126 459,84 580,84 630,84 678,90 723,101 768,112 809,125 846,142 L 846,37 C 812,20 773,6 729,-5 685,-15 636,-20 580,-20 Z"
|
||||
id="glyph38" />
|
||||
<glyph
|
||||
unicode="a"
|
||||
horiz-adv-x="822"
|
||||
d="M 535,1108 C 651,1108 737,1078 795,1018 852,958 881,863 881,734 L 881,0 793,0 772,185 766,185 C 729,123 684,74 631,36 578,-1 503,-20 408,-20 311,-20 233,6 176,59 119,111 90,187 90,285 90,394 132,477 215,533 298,589 420,621 580,629 L 764,639 764,715 C 764,822 744,897 705,942 665,987 606,1010 528,1010 477,1010 426,1002 378,987 329,972 281,953 231,928 L 195,1022 C 242,1047 295,1067 352,1084 410,1100 470,1108 535,1108 Z M 594,543 C 466,536 370,512 307,470 244,429 213,367 213,285 213,217 232,165 271,131 310,96 363,78 430,78 535,78 617,111 676,176 735,240 764,330 764,445 L 764,551 594,543 Z"
|
||||
id="glyph40" />
|
||||
<glyph
|
||||
unicode="S"
|
||||
horiz-adv-x="875"
|
||||
d="M 956,381 C 956,294 936,220 894,160 852,100 796,55 724,25 652,-5 571,-20 479,-20 396,-20 324,-14 262,-2 201,11 147,26 102,46 L 102,162 C 152,142 209,124 273,109 338,94 409,87 485,87 589,87 673,110 738,158 803,206 836,278 836,373 836,431 823,478 798,515 772,553 734,586 682,614 630,642 565,670 485,699 410,726 345,757 291,791 236,825 194,868 164,919 134,970 119,1035 119,1112 119,1192 138,1259 176,1314 214,1369 267,1411 333,1440 399,1469 474,1483 559,1483 626,1483 689,1476 750,1463 810,1449 868,1430 924,1405 L 883,1303 C 772,1352 663,1377 555,1377 462,1377 386,1354 328,1310 269,1266 240,1200 240,1114 240,1052 252,1001 278,964 303,926 340,895 389,869 438,843 498,817 567,791 648,762 717,731 775,698 833,664 878,623 909,573 941,523 956,459 956,381 Z"
|
||||
id="glyph42" />
|
||||
<glyph
|
||||
unicode="P"
|
||||
horiz-adv-x="848"
|
||||
d="M 539,1462 C 869,1462 1034,1325 1034,1049 1034,908 992,798 907,718 823,638 690,598 510,598 L 311,598 311,0 193,0 193,1462 539,1462 Z M 528,1358 L 311,1358 311,702 498,702 C 629,702 730,727 803,776 875,825 911,914 911,1043 911,1152 880,1232 818,1282 756,1333 659,1358 528,1358 Z"
|
||||
id="glyph44" />
|
||||
<glyph
|
||||
unicode="E"
|
||||
horiz-adv-x="769"
|
||||
d="M 950,0 L 193,0 193,1462 950,1462 950,1356 311,1356 311,821 913,821 913,715 311,715 311,107 950,107 950,0 Z"
|
||||
id="glyph46" />
|
||||
<glyph
|
||||
unicode=" "
|
||||
horiz-adv-x="503"
|
||||
id="glyph48" />
|
||||
</font></defs>
|
||||
<defs
|
||||
class="TextShapeIndex"
|
||||
id="defs55" />
|
||||
<defs
|
||||
class="EmbeddedBulletChars"
|
||||
id="defs87" />
|
||||
|
||||
<g
|
||||
id="id10"
|
||||
clip-path="none"
|
||||
transform="translate(-700.00001,-2550)">
|
||||
|
||||
<text
|
||||
class="SVGTextShape"
|
||||
id="text151"
|
||||
x="217.60002"
|
||||
y="-56.506969"
|
||||
style="letter-spacing:4.7625px;word-spacing:104.775px"><tspan
|
||||
class="TextParagraph"
|
||||
font-family="'Noto Sans Display Light', sans-serif"
|
||||
font-size="494px"
|
||||
font-weight="400"
|
||||
id="tspan149"><tspan
|
||||
class="TextPosition"
|
||||
x="650.59998"
|
||||
y="7647.4932"
|
||||
id="tspan147"><tspan
|
||||
fill="#808080"
|
||||
stroke="none"
|
||||
style="white-space:pre"
|
||||
id="tspan145"
|
||||
dx="2.1199999">Podcast Synchronisation made Efficient</tspan></tspan></tspan></text>
|
||||
</g><g
|
||||
id="g1277"
|
||||
transform="translate(-700.00001,-2550)"><path
|
||||
id="path131-3"
|
||||
d="m 6694.0006,4763 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1166 989.0352,986.0379 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.1649 -719.0259,-748.0163 12.7874,-421.0793 236.9242,-746.3999 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.9957,0 V 4763 Z"
|
||||
style="fill:#0084d1;fill-opacity:1"
|
||||
clip-path="none" /><path
|
||||
id="path131"
|
||||
d="m 6685.0183,2562.996 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1167 989.0352,986.038 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.165 -719.0259,-748.0164 12.7874,-421.0792 236.9242,-746.3998 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.996,0 V 2562.996 Z"
|
||||
style="fill:#0084d1;fill-opacity:1"
|
||||
clip-path="none" /></g><g
|
||||
id="g1263"
|
||||
transform="translate(-700.00001,-2550)"><path
|
||||
fill="none"
|
||||
stroke="#069a2e"
|
||||
stroke-width="265"
|
||||
stroke-linejoin="round"
|
||||
d="m 2793,5962 c 1283,0 429,-2762 1712,-2762"
|
||||
id="path124" /><path
|
||||
id="path110-6"
|
||||
d="M 3198.0212,6550 V 6300.0411 H 2448.0411 V 6050.0305 5550.0094 H 2198.0305 V 6300.0411 6550 H 2448.0411 2698 Z"
|
||||
style="fill:#069a2e;fill-opacity:1" /><path
|
||||
id="path110"
|
||||
d="m 4111.997,2550.0252 v 249.9589 h 749.9801 v 250.0106 500.0211 h 250.0106 v -750.0317 -249.9589 h -250.0106 -249.9589 z"
|
||||
style="fill:#069a2e;fill-opacity:1" /></g>
|
||||
<g
|
||||
id="g1249"
|
||||
transform="translate(-700.00001,-2550)"><path
|
||||
fill="#ff8000"
|
||||
stroke="none"
|
||||
d="M 2215,4164 C 2412.6918,3832.6035 2379.3124,3383.7591 2135.4189,3084.8193 1956.8564,2857.4026 1671.3097,2718.8851 1382,2721 c 0,-52.6667 0,-105.3333 0,-158 -60.1303,-1.0792 190.6585,-1.2724 121.9814,2.7933 434.6311,30.3756 832.6257,336.7309 974.9655,748.2365 148.7336,402.6249 41.0263,883.7477 -266.0719,1183.8452 C 1996.6852,4716.1853 1689.0048,4838.6187 1382,4830 c 0,-61.6667 0,-123.3333 0,-185 338.199,2.9253 666.226,-186.816 833,-481 z"
|
||||
id="path193" /><path
|
||||
fill="#ff8000"
|
||||
stroke="none"
|
||||
d="m 1936,3979 c 175.8129,-283.3241 59.7943,-700.6319 -239.8255,-849.407 -94.2713,-50.9942 -201.887,-77.9344 -309.1745,-74.593 0,-57 0,-114 0,-171 396.3865,-24.0968 777.5367,297.6517 818.5878,693.1841 44.0348,337.5467 -149.4277,694.9971 -466.4953,826.9493 -110.1027,49.0687 -231.5272,73.543 -352.0925,67.8666 0,-61.6667 0,-123.3333 0,-185 220.6353,7.5804 440.8554,-115.3286 549,-308 z"
|
||||
id="path186" /><path
|
||||
fill="#ff8000"
|
||||
stroke="none"
|
||||
d="m 1659,3822 c 86.3933,-138.0398 18.2474,-344.669 -134.6962,-402.3205 C 1483.44,3402.2177 1438.3524,3394.2432 1394,3398 c 0,-56.6667 0,-113.3333 0,-170 223.1964,-19.6143 444.7886,153.3254 478.4886,375.1817 32.646,181.6951 -54.6854,381.4331 -217.3127,472.2205 -78.2316,46.131 -170.3991,69.3119 -261.1759,62.5978 0,-58.3333 0,-116.6667 0,-175 105.6736,9.5509 212.8962,-49.2218 265,-141 z"
|
||||
id="path179" /><rect
|
||||
class="BoundingBox"
|
||||
stroke="none"
|
||||
fill="none"
|
||||
x="700"
|
||||
y="2550"
|
||||
width="501"
|
||||
height="4001"
|
||||
id="rect136"
|
||||
style="fill:#ff8000;fill-opacity:1" /></g>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 13 KiB |
BIN
00-pflichtenheft/assets/ui/help-desktop.png
Normal file
After Width: | Height: | Size: 190 KiB |
After Width: | Height: | Size: 211 KiB |
BIN
00-pflichtenheft/assets/ui/listening-progress-desktop.png
Normal file
After Width: | Height: | Size: 201 KiB |
BIN
00-pflichtenheft/assets/ui/listening-progress-mobile.png
Normal file
After Width: | Height: | Size: 354 KiB |
BIN
00-pflichtenheft/assets/ui/login-desktop.png
Normal file
After Width: | Height: | Size: 138 KiB |
BIN
00-pflichtenheft/assets/ui/login-mobile.png
Normal file
After Width: | Height: | Size: 207 KiB |
BIN
00-pflichtenheft/assets/ui/podcasts-desktop-change-language.png
Normal file
After Width: | Height: | Size: 426 KiB |
BIN
00-pflichtenheft/assets/ui/podcasts-desktop.png
Normal file
After Width: | Height: | Size: 419 KiB |
BIN
00-pflichtenheft/assets/ui/podcasts-mobile.png
Normal file
After Width: | Height: | Size: 338 KiB |
BIN
00-pflichtenheft/assets/ui/settings-desktop-1.png
Normal file
After Width: | Height: | Size: 193 KiB |
BIN
00-pflichtenheft/assets/ui/settings-desktop-2.png
Normal file
After Width: | Height: | Size: 183 KiB |
BIN
00-pflichtenheft/assets/ui/settings-mobile-1.png
Normal file
After Width: | Height: | Size: 284 KiB |
BIN
00-pflichtenheft/assets/ui/settings-mobile-2.png
Normal file
After Width: | Height: | Size: 291 KiB |
94
00-pflichtenheft/pflichtenheft.tex
Normal file
|
@ -0,0 +1,94 @@
|
|||
% \documentclass[a4paper, UTF8, 12pt]{article}
|
||||
% \documentclass[a4paper, UTF8, 12pt]{scrbook}
|
||||
\documentclass[parskip=half, a4paper, 12pt]{scrartcl}
|
||||
|
||||
\usepackage[german]{babel}
|
||||
\usepackage[dvipsnames]{xcolor}
|
||||
\usepackage{tikz}
|
||||
\usetikzlibrary{positioning}
|
||||
\usetikzlibrary{calc}
|
||||
\usetikzlibrary{arrows}
|
||||
\usetikzlibrary{intersections}
|
||||
\usepackage{tikz-uml}
|
||||
\usepackage{pgf-umlsd}
|
||||
\usepgflibrary{arrows} % for pgf-umlsd
|
||||
\tikzumlset{fill usecase=white}
|
||||
\usepackage[margin=2.5cm]{geometry}
|
||||
\usepackage{csquotes}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{amsmath}
|
||||
\usepackage{pdflscape}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{caption}
|
||||
\usepackage{subcaption}
|
||||
\usepackage{float}
|
||||
\usepackage{enumitem}
|
||||
\usepackage{textpos}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{fancyhdr}
|
||||
\usepackage{multicol}
|
||||
|
||||
\hypersetup{
|
||||
% ‘texdoc hyperref‘ for options
|
||||
pdftitle={
|
||||
PSE\textsuperscript{2}
|
||||
- Podcast Synchronisation made Efficient Pflichtenheft
|
||||
},
|
||||
bookmarks=true,
|
||||
}
|
||||
\usepackage{csquotes}
|
||||
\usepackage[toc]{glossaries}
|
||||
\usepackage{lastpage}
|
||||
|
||||
\include{sections/glossar}
|
||||
|
||||
\title{Pflichtenheft}
|
||||
\author{KIT Students et al}
|
||||
\date{2.12.2022}
|
||||
|
||||
\pagestyle{fancy}
|
||||
\setkomafont{pageheadfoot}{\footnotesize\scshape}
|
||||
\fancyhead{} % clear all header fields
|
||||
% \fancyhead[L]{Pflichtenheft}
|
||||
\fancyhead[L]{PSE\textsuperscript{2} - Podcast Synchronisation made Efficient}
|
||||
% \fancyhead[R]{2.12.2022}
|
||||
\fancyfoot{} % clear all footer fields
|
||||
\fancyfoot[R]{\thepage{} / \pageref{LastPage}}
|
||||
\fancyfoot[L]{Praxis der Softwareentwicklung}
|
||||
\fancyfoot[C]{}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\include{titlepage}
|
||||
\setcounter{page}{1}
|
||||
|
||||
\tableofcontents
|
||||
|
||||
\include{sections/einleitung}
|
||||
\newpage
|
||||
|
||||
\include{sections/anforderungsanalyse}
|
||||
\newpage
|
||||
|
||||
\include{sections/2-produkteinsatz}
|
||||
\newpage
|
||||
|
||||
\include{sections/produktuebersicht}
|
||||
\newpage
|
||||
|
||||
\include{sections/produktfunktionen}
|
||||
\newpage
|
||||
|
||||
\include{sections/produktdaten}
|
||||
\newpage
|
||||
|
||||
\include{sections/benutzeroberflaeche}
|
||||
\newpage
|
||||
|
||||
\include{sections/tests}
|
||||
\newpage
|
||||
|
||||
\printglossaries
|
||||
\glsaddall
|
||||
|
||||
\end{document}
|
329
00-pflichtenheft/pgf-umlsd.sty
Normal file
|
@ -0,0 +1,329 @@
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Start of pgf-umlsd.sty
|
||||
%
|
||||
% Some macros for UML Sequence Diagrams.
|
||||
% Home page of project: http://pgf-umlsd.googlecode.com/
|
||||
% Author: Xu Yuan <xuyuan.cn@gmail.com>, Southeast University, China
|
||||
% Contributor: Nobel Huang <nobel1984@gmail.com>, Southeast University, China
|
||||
%
|
||||
% History:
|
||||
% v0.7 2012/03/05
|
||||
% - unify interface of call and callself
|
||||
% - non-instantaneous message
|
||||
% - bugfix: conflits with tikz library backgrounds
|
||||
% v0.6 2011/07/27
|
||||
% - Fix Issue 6 reported by frankmorgner@gmail.com
|
||||
% - diagram without a thread
|
||||
% - allows empty diagram
|
||||
% - New manual
|
||||
% v0.5 2009/09/30 Fix Issue 2 reported by vlado.handziski
|
||||
% - Nested callself is supported
|
||||
% - Rename sdloop and sdframe to sdblock
|
||||
% v0.4 2008/12/08 Fix Issue 1 reported by MathStuf:
|
||||
% Nested sdloop environment hides outer loop
|
||||
% v0.3 2008/11/10 in Berlin, fix for the PGF cvs version:
|
||||
% - the list items in \foreach are not evaluated by default now,
|
||||
% the `evaluate' opinion should be used
|
||||
% v0.2 2008/03/20 create project at http://pgf-umlsd.googlecode.com/
|
||||
% - use `shadows' library
|
||||
% Thanks for Dr. Ludger Humbert's <humbert@uni-wuppertal.de> feedback!
|
||||
% - reduce the parameter numbers, the user can write the content
|
||||
% of instance (such as no colon)
|
||||
% - the user can redefine the `inststyle'
|
||||
% - new option: switch underlining of the instance text
|
||||
% - new option: switch rounded corners
|
||||
% v0.1 2008/01/25 first release at http://www.fauskes.net/pgftikzexamples/
|
||||
%
|
||||
|
||||
\NeedsTeXFormat{LaTeX2e}[1999/12/01]
|
||||
\ProvidesPackage{pgf-umlsd}[2011/07/27 v0.6 Some LaTeX macros for UML
|
||||
Sequence Diagrams.]
|
||||
|
||||
\RequirePackage{tikz}
|
||||
\usetikzlibrary{arrows,shadows}
|
||||
|
||||
\RequirePackage{ifthen}
|
||||
|
||||
% Options
|
||||
% ? the instance name under line ?
|
||||
\newif\ifpgfumlsdunderline\pgfumlsdunderlinetrue
|
||||
\DeclareOption{underline}{\pgfumlsdunderlinetrue}
|
||||
\DeclareOption{underline=true}{\pgfumlsdunderlinetrue}
|
||||
\DeclareOption{underline=false}{\pgfumlsdunderlinefalse}
|
||||
% ? the instance box with rounded corners ?
|
||||
\newif\ifpgfumlsdroundedcorners\pgfumlsdroundedcornersfalse
|
||||
\DeclareOption{roundedcorners}{\pgfumlsdroundedcornerstrue}
|
||||
\DeclareOption{roundedcorners=true}{\pgfumlsdroundedcornerstrue}
|
||||
\DeclareOption{roundedcorners=false}{\pgfumlsdroundedcornersfalse}
|
||||
\ProcessOptions
|
||||
|
||||
% new counters
|
||||
\newcounter{preinst}
|
||||
\newcounter{instnum}
|
||||
\newcounter{threadnum}
|
||||
\newcounter{seqlevel} % level
|
||||
\newcounter{callevel}
|
||||
\newcounter{callselflevel}
|
||||
\newcounter{blocklevel}
|
||||
|
||||
% new an instance
|
||||
% Example:
|
||||
% \newinst[edge distance]{var}{name:class}
|
||||
\newcommand{\newinst}[3][0.2]{
|
||||
\stepcounter{instnum}
|
||||
\path (inst\thepreinst.east)+(#1,0) node[inststyle] (inst\theinstnum)
|
||||
{\ifpgfumlsdunderline
|
||||
\underline{#3}
|
||||
\else
|
||||
#3
|
||||
\fi};
|
||||
\path (inst\theinstnum)+(0,-0.5*\unitfactor) node (#2) {};
|
||||
\tikzstyle{instcolor#2}=[]
|
||||
\stepcounter{preinst}
|
||||
}
|
||||
|
||||
% new an instance thread
|
||||
% Example:
|
||||
% \newinst[color]{var}{name}{class}
|
||||
\newcommand{\newthread}[3][gray!30]{
|
||||
\newinst{#2}{#3}
|
||||
\stepcounter{threadnum}
|
||||
\node[below of=inst\theinstnum,node distance=0.8cm] (thread\thethreadnum) {};
|
||||
\tikzstyle{threadcolor\thethreadnum}=[fill=#1]
|
||||
\tikzstyle{instcolor#2}=[fill=#1]
|
||||
}
|
||||
|
||||
% draw running (thick) line, should not call directly
|
||||
\newcommand*{\drawthread}[2]{
|
||||
\begin{pgfonlayer}{umlsd@threadlayer}
|
||||
\draw[threadstyle] (#1.west) -- (#1.east) -- (#2.east) -- (#2.west) -- cycle;
|
||||
\end{pgfonlayer}
|
||||
}
|
||||
|
||||
% a function call
|
||||
% Example:
|
||||
% \begin{call}[height]{caller}{function}{callee}{return}
|
||||
% \end{call}
|
||||
\newenvironment{call}[5][1]{
|
||||
\ifthenelse{\equal{#2}{#4}}
|
||||
{
|
||||
\begin{callself}[#1]{#2}{#3}{#5}
|
||||
}
|
||||
{
|
||||
\begin{callanother}[#1]{#2}{#3}{#4}{#5}
|
||||
}
|
||||
}
|
||||
{
|
||||
\ifthenelse{\equal{\f\thecallevel}{\t\thecallevel}}
|
||||
{
|
||||
\end{callself}
|
||||
}
|
||||
{
|
||||
\end{callanother}
|
||||
}
|
||||
}
|
||||
|
||||
% function call to another instance
|
||||
% interal use only
|
||||
\newenvironment*{callanother}[5][1]{
|
||||
\stepcounter{seqlevel}
|
||||
\stepcounter{callevel} % push
|
||||
\path
|
||||
(#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {}
|
||||
(#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {};
|
||||
|
||||
\draw[->,>=triangle 60] ({cf\thecallevel}) -- (ct\thecallevel)
|
||||
node[midway, above] {#3};
|
||||
\def\l\thecallevel{#1}
|
||||
\def\f\thecallevel{#2}
|
||||
\def\t\thecallevel{#4}
|
||||
\def\returnvalue{#5}
|
||||
\tikzstyle{threadstyle}+=[instcolor#2]
|
||||
}
|
||||
{
|
||||
\addtocounter{seqlevel}{\l\thecallevel}
|
||||
\path
|
||||
(\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {}
|
||||
(\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rt\thecallevel) {};
|
||||
\draw[dashed,->,>=angle 60] ({rt\thecallevel}) -- (rf\thecallevel)
|
||||
node[midway, above]{\returnvalue};
|
||||
\drawthread{ct\thecallevel}{rt\thecallevel}
|
||||
\addtocounter{callevel}{-1} % pop
|
||||
}
|
||||
|
||||
% a function do not need call others
|
||||
% interal use only
|
||||
% Example:
|
||||
% \begin{callself}[height]{caller}{function}{return}
|
||||
% \end{callself}
|
||||
\newenvironment*{callself}[4][1]{
|
||||
\stepcounter{seqlevel}
|
||||
\stepcounter{callevel} % push
|
||||
\stepcounter{callselflevel}
|
||||
|
||||
\path
|
||||
(#2)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (sc\thecallevel) {}
|
||||
({sc\thecallevel}.east)+(0,-0.33*\unitfactor) node (scb\thecallevel) {};
|
||||
|
||||
\draw[->,>=triangle 60] ({sc\thecallevel}.east) -- ++(0.8,0)
|
||||
node[near start, above right] {#3} -- ++(0,-0.33*\unitfactor)
|
||||
-- (scb\thecallevel);
|
||||
\def\l\thecallevel{#1}
|
||||
\def\f\thecallevel{#2}
|
||||
\def\t\thecallevel{#2}
|
||||
\def\returnvalue{#4}
|
||||
\tikzstyle{threadstyle}+=[instcolor#2]
|
||||
}{
|
||||
\addtocounter{seqlevel}{\l\thecallevel}
|
||||
\path (\f\thecallevel)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.33*\unitfactor) node
|
||||
(sct\thecallevel) {};
|
||||
|
||||
\draw[dashed,->,>=angle 60] ({sct\thecallevel}.east) node
|
||||
(sce\thecallevel) {} -- ++(0.8,0) -- node[midway, right]{\returnvalue} ++(0,-0.33*\unitfactor) -- ++(-0.8,0);
|
||||
\drawthread{scb\thecallevel}{sce\thecallevel}
|
||||
\addtocounter{callevel}{-1} % pop
|
||||
\addtocounter{callselflevel}{-1}
|
||||
}
|
||||
|
||||
% message between threads
|
||||
% Example:
|
||||
% \mess[delay]{sender}{message content}{receiver}
|
||||
\newcommand{\mess}[4][0]{
|
||||
\stepcounter{seqlevel}
|
||||
\path
|
||||
(#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess from) {};
|
||||
\addtocounter{seqlevel}{#1}
|
||||
\path
|
||||
(#4)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess to) {};
|
||||
\draw[->,>=angle 60] (mess from) -- (mess to) node[midway, above]
|
||||
{#3};
|
||||
|
||||
\node (#3 from) at (mess from) {};
|
||||
\node (#3 to) at (mess to) {};
|
||||
}
|
||||
|
||||
\newenvironment{messcall}[4][1]{
|
||||
\stepcounter{seqlevel}
|
||||
\stepcounter{callevel} % push
|
||||
\path
|
||||
(#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {}
|
||||
(#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {};
|
||||
|
||||
\draw[->,>=angle 60] ({cf\thecallevel}) -- (ct\thecallevel)
|
||||
node[midway, above] {#3};
|
||||
\def\l\thecallevel{#1}
|
||||
\def\f\thecallevel{#2}
|
||||
\def\t\thecallevel{#4}
|
||||
\tikzstyle{threadstyle}+=[instcolor#2]
|
||||
}
|
||||
{
|
||||
\addtocounter{seqlevel}{\l\thecallevel}
|
||||
\path
|
||||
(\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {}
|
||||
(\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.3*\unitfactor) node (rt\thecallevel) {};
|
||||
\drawthread{ct\thecallevel}{rt\thecallevel}
|
||||
\addtocounter{callevel}{-1} % pop
|
||||
}
|
||||
|
||||
% In the situation of multi-threads, some objects are called at the
|
||||
% same time. Currently, we have to adjust the bias of thread line
|
||||
% manually. Possible parameters are: center, west, east
|
||||
\newcommand{\setthreadbias}[1]{\global\def\threadbias{#1}}
|
||||
|
||||
% This function makes the call earlier.
|
||||
\newcommand{\prelevel}{\addtocounter{seqlevel}{-1}}
|
||||
|
||||
% This function makes the call later.
|
||||
\newcommand{\postlevel}{\addtocounter{seqlevel}{+1}}
|
||||
|
||||
% a block box with caption
|
||||
% \begin{sdblock}[caption background color]{caption}{comments}
|
||||
% \end{sdblock}
|
||||
\newenvironment{sdblock}[3][white]{
|
||||
\stepcounter{seqlevel}
|
||||
\stepcounter{blocklevel} % push
|
||||
\coordinate (blockbeg\theblocklevel) at (0,-\theseqlevel*\unitfactor-\unitfactor);
|
||||
\stepcounter{seqlevel}
|
||||
\def\blockcolor\theblocklevel{#1}
|
||||
\def\blockname\theblocklevel{#2}
|
||||
\def\blockcomm\theblocklevel{#3}
|
||||
\begin{pgfinterruptboundingbox}
|
||||
}{
|
||||
\coordinate (blockend) at (0,-\theseqlevel*\unitfactor-2*\unitfactor);
|
||||
\path (current bounding box.east)+(0.2,0) node (boxeast) {}
|
||||
(current bounding box.west |- {blockbeg\theblocklevel}) + (-0.2,0)
|
||||
node (nw) {};
|
||||
\path (boxeast |- blockend) node (se) {};
|
||||
|
||||
% % title
|
||||
\node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel};
|
||||
\path (blocktitle.south east) + (0,0.2) node (set) {}
|
||||
(blocktitle.south east) + (-0.2,0) node (seb) {}
|
||||
(blocktitle.north east) + (0.2,0) node (comm) {};
|
||||
\draw[fill=\blockcolor\theblocklevel] (blocktitle.north west) -- (blocktitle.north east) --
|
||||
(set.center) -- (seb.center) -- (blocktitle.south west) -- cycle;
|
||||
\node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel};
|
||||
\node[blockcommentstyle] (blockcomment) at (comm) {\blockcomm\theblocklevel};
|
||||
|
||||
\coordinate (se) at (current bounding box.south east);
|
||||
\end{pgfinterruptboundingbox}
|
||||
|
||||
\draw (se) rectangle (nw);
|
||||
|
||||
\addtocounter{blocklevel}{-1} % pop
|
||||
\stepcounter{seqlevel}
|
||||
}
|
||||
|
||||
% the environment of sequence diagram
|
||||
\newenvironment{sequencediagram}{
|
||||
% declare layers
|
||||
\pgfdeclarelayer{umlsd@background}
|
||||
\pgfdeclarelayer{umlsd@threadlayer}
|
||||
\pgfsetlayers{umlsd@background,umlsd@threadlayer,main}
|
||||
|
||||
\begin{tikzpicture}
|
||||
\setlength{\unitlength}{1cm}
|
||||
\tikzstyle{sequence}=[coordinate]
|
||||
\tikzstyle{inststyle}=[rectangle, draw, anchor=west, minimum
|
||||
height=0.8cm, minimum width=1.6cm, fill=white,
|
||||
drop shadow={opacity=1,fill=black}]
|
||||
\ifpgfumlsdroundedcorners
|
||||
\tikzstyle{inststyle}+=[rounded corners=3mm]
|
||||
\fi
|
||||
\tikzstyle{blockstyle}=[anchor=north west]
|
||||
\tikzstyle{blockcommentstyle}=[anchor=north west, font=\small]
|
||||
\tikzstyle{dot}=[inner sep=0pt,fill=black,circle,minimum size=0.2pt]
|
||||
\global\def\unitfactor{0.6}
|
||||
\global\def\threadbias{center}
|
||||
% reset counters
|
||||
\setcounter{preinst}{0}
|
||||
\setcounter{instnum}{0}
|
||||
\setcounter{threadnum}{0}
|
||||
\setcounter{seqlevel}{0}
|
||||
\setcounter{callevel}{0}
|
||||
\setcounter{callselflevel}{0}
|
||||
\setcounter{blocklevel}{0}
|
||||
|
||||
% origin
|
||||
\node[coordinate] (inst0) {};
|
||||
}
|
||||
{
|
||||
\begin{pgfonlayer}{umlsd@background}
|
||||
\ifnum\c@instnum > 0
|
||||
\foreach \t [evaluate=\t] in {1,...,\theinstnum}{
|
||||
\draw[dotted] (inst\t) -- ++(0,-\theseqlevel*\unitfactor-2.2*\unitfactor);
|
||||
}
|
||||
\fi
|
||||
\ifnum\c@threadnum > 0
|
||||
\foreach \t [evaluate=\t] in {1,...,\thethreadnum}{
|
||||
\path (thread\t)+(0,-\theseqlevel*\unitfactor-0.1*\unitfactor) node (threadend) {};
|
||||
\tikzstyle{threadstyle}+=[threadcolor\t]
|
||||
\drawthread{thread\t}{threadend}
|
||||
}
|
||||
\fi
|
||||
\end{pgfonlayer}
|
||||
\end{tikzpicture}}
|
||||
|
||||
|
||||
%%% End of pgf-umlsd.sty
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
73
00-pflichtenheft/sections/2-produkteinsatz.tex
Normal file
|
@ -0,0 +1,73 @@
|
|||
\section{Produkteinsatz}
|
||||
|
||||
Im Folgenden werden Anwendungsbereiche, Zielgruppen und Betriebsbedingungen des
|
||||
Produkts geschildert.
|
||||
|
||||
\subsection{Anwendungsbereiche}
|
||||
|
||||
Der \Gls{podcast}-Synchronisationsserver dient dazu,
|
||||
Betreibern von \Glspl{podcatcher} einen performanteren und schlankeren
|
||||
Synchronisationsdienst zur Verfügung zu stellen, als aktuell erhältliche Synchronisationsserver.
|
||||
Die Nutzer erhalten außerdem eine einfach zu bedienende und übersichtliche Möglichkeit,
|
||||
ihre abonnierten \Glspl{podcast} über mehrere Geräte hinweg synchronisieren zu können.
|
||||
|
||||
Damit das Produkt seinen Ansprüchen in Sachen Performanz und Nutzerfreundlichkeit
|
||||
gerecht werden kann, wird ausdrücklich auf Features, die nicht zur Kernaufgabe gehören,
|
||||
was die Synchronisation von \Glspl{podcast} ist, verzichtet.
|
||||
Dazu gehören zum Beispiel Funktionalitäten, wie das Suchen von \Glspl{podcast} oder das
|
||||
Anhören von \Glspl{episode}, welche nicht bereitgestellt werden.
|
||||
Außerdem werden keine extra Konfigurationsmöglichkeiten für die Synchronisation angeboten.
|
||||
|
||||
Es wird eine Schnittstelle in Form einer graphischen Weboberfläche
|
||||
bereitgestellt, mithilfe welcher der Nutzer seinen Account verwalten und
|
||||
synchronisierte \Glspl{podcast} einsehen kann.
|
||||
Für die Synchronisation wird der Account mit einer oder mehreren \Gls{podcatcher}-Applikationen
|
||||
verknüpft.
|
||||
Dadurch werden lokal gespeicherte \Glspl{abo} und Abhörfortschritte auf den
|
||||
Account und somit auf alle verknüpften \Gls{podcatcher} übertragen.
|
||||
|
||||
|
||||
\subsection{Zielgruppen}
|
||||
Zur Zielgruppe gehören Betreiber von \Gls{podcatcher}-Applikationen und deren Nutzer.
|
||||
Durch den Synchronisationsserver können die Betreiber ihren Nutzern eine
|
||||
schlanke und einfach bedienbare Möglichkeit zum Synchronisieren ihrer abonnierten
|
||||
\Glspl{podcast} bieten.
|
||||
|
||||
\subsection{Betriebsbedingungen}
|
||||
Es müssen folgende Voraussetzungen auf Server- und Nutzerseite erfüllt sein.
|
||||
|
||||
%\newcommand{\tabitem}{\vspace{.1cm}~~\llap{\textbullet}~~}
|
||||
%\begin{tabular}{l l}
|
||||
% Server: & Nutzer: \\
|
||||
% % \hline
|
||||
% \tabitem Internetanbindung &
|
||||
% \tabitem Internetanbindung \\
|
||||
% \tabitem Speicherplatz: mind. 12GB &
|
||||
% \tabitem Aktueller Webbrowser \\
|
||||
% \tabitem Arbeitsspeicher: mind. 2GB &
|
||||
% \tabitem \Gls{podcatcher} mit \Gls{gpodder} Unterstützung \\
|
||||
% \tabitem CPU: mind. 2 Kerne & \\
|
||||
% \tabitem JVM-Fähig (\Gls{java} 17) & \\
|
||||
% \tabitem MariaDB-Fähig (MariaDB Server 10.6) & \\
|
||||
%\end{tabular}
|
||||
|
||||
\begin{multicols}{2}
|
||||
Server:
|
||||
\begin{itemize}
|
||||
\item Speicherplatz: mind. 12GB
|
||||
\item Arbeitsspeicher: mind. 2GB
|
||||
\item CPU: mind. 2 Kerne
|
||||
\item JVM-Fähig (\Gls{java} 17)
|
||||
\item MariaDB-Fähig \\ (MariaDB Server 10.6)
|
||||
\end{itemize}
|
||||
\columnbreak
|
||||
Nutzer:
|
||||
\begin{itemize}
|
||||
\item Internetanbindung
|
||||
\item Aktueller Webbrowser
|
||||
\item \Gls{podcatcher} mit \Gls{gpodder} Unterstützung
|
||||
\item[]
|
||||
\item[]
|
||||
\end{itemize}
|
||||
\end{multicols}
|
||||
|
56
00-pflichtenheft/sections/TikzPictures/ActivityLogin.tex
Normal file
|
@ -0,0 +1,56 @@
|
|||
\begin{tikzpicture}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Nodeklassen für Aktivitätsdiagramm festlegen: %
|
||||
%-------------------------------------------------------------------------------%
|
||||
% start - Schwarzer ausgefüllter Kreis %
|
||||
% activity - Abgerundetes Rechteck für Aktivitäten des Users %
|
||||
% actBox - Rechteck für Reaktionen des Systems %
|
||||
% decision - Karokästchen für Entscheidungen / Abzweigungen %
|
||||
% end - Zielscheibe für das Ende der Aktivität %
|
||||
%-------------------------------------------------------------------------------%
|
||||
% Siehe: https://www-kseta.ttp.kit.edu/fellows/Tanja.Harbaum/tikz_tutorial.pdf %
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
\tikzset{start/.style={circle,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
|
||||
\tikzset{activity/.style={rectangle,minimum width=1cm,minimum height=0.5cm,rounded corners=5pt,draw,align=center}}
|
||||
\tikzset{actBox/.style={rectangle,minimum width=1cm,minimum height=0.5cm,draw,align=center}}
|
||||
\tikzset{decision/.style={diamond,minimum width=1cm,minimum height=1cm,draw,align=center}}
|
||||
\tikzset{end/.style={draw,double=white,circle,inner sep=1pt,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
|
||||
|
||||
% Nodes und deren Position (voneinander abhängig) angeben
|
||||
\node[start] (Start) {};
|
||||
\node[activity, right = of Start] (Aufruf) {Website aufrufen};
|
||||
\node[actBox, right = of Aufruf] (Login) {Login page};
|
||||
\node[decision, right = of Login] (Remembered) {Gemerkt?};
|
||||
\node[decision, below left = of Remembered] (RemEnd1) {};
|
||||
\node[activity, below = of RemEnd1] (Input) {E-Mail und\\ Passwort eingeben};
|
||||
\node[activity, below = of Input] (RememberOpt) {Option \string"Passwort merken\string"\\ aus-/abwählen};
|
||||
\node[activity, below = of RememberOpt] (LoginPress) {\string"Anmelden\string"-Button\\ drücken};
|
||||
\node[actBox, left = of LoginPress] (ErrorBox) {Fehlermeldung};
|
||||
\node[decision, below = of LoginPress] (CorrectEntry) {Korrekte\\ Eingabe?};
|
||||
\node[actBox, right = of CorrectEntry] (DashboardShow) {Dashboard\\ der Website};
|
||||
\path[name path=P1] (Remembered.south east) -| (DashboardShow);
|
||||
\path[name path=P2] (RemEnd1.north east) -| (DashboardShow);
|
||||
\node[end, below = of DashboardShow] (End) {};
|
||||
\coordinate (jump1) at (DashboardShow |- RemEnd1){};
|
||||
\draw($(Start.north west)+(-1,2)$) rectangle ($(End.south east)+(2,-1)$);
|
||||
\path ($(Start.north west)+(-1,1.3)$) -- ($(Start -| End)+(2,1.3)$) node[midway]{\Large \textbf{Anmeldung}};
|
||||
|
||||
% Verbindungen zwischen den Nodes
|
||||
|
||||
\draw[-stealth, thick](Start) -- (Aufruf);
|
||||
\draw[-stealth, thick](Aufruf) -- (Login);
|
||||
\draw[-stealth, thick](Login) -- (Remembered);
|
||||
\draw[-stealth, thick](Remembered) -- node[left = 2mm, very near start]{nein} (RemEnd1);
|
||||
\draw[-stealth, thick](Remembered.south east) -- (jump1) node[right = 2mm, near start]{ja} -- (DashboardShow);
|
||||
\draw[-stealth, thick](RemEnd1) -- (Input);
|
||||
\draw[-stealth, thick](Input) -- (RememberOpt);
|
||||
\draw[-stealth, thick](RememberOpt) -- (LoginPress);
|
||||
\draw[-stealth, thick](LoginPress) -- (CorrectEntry);
|
||||
\draw[-stealth, thick](CorrectEntry) -| node[above, very near start]{falsch} (ErrorBox);
|
||||
\draw[-stealth, thick](ErrorBox) |- (RemEnd1);
|
||||
\draw[-stealth, thick](CorrectEntry) -- node[above, midway]{wahr} (DashboardShow);
|
||||
\draw[-stealth, thick](DashboardShow) -- (End);
|
||||
|
||||
\end{tikzpicture}
|
60
00-pflichtenheft/sections/TikzPictures/ActivityRegister.tex
Normal file
|
@ -0,0 +1,60 @@
|
|||
\begin{tikzpicture}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Nodeklassen für Aktivitätsdiagramm festlegen: %
|
||||
%-------------------------------------------------------------------------------%
|
||||
% start - Schwarzer ausgefüllter Kreis %
|
||||
% activity - Abgerundetes Rechteck für Aktivitäten des Users %
|
||||
% actBox - Rechteck für Reaktionen des Systems %
|
||||
% decision - Karokästchen für Entscheidungen / Abzweigungen %
|
||||
% end - Zielscheibe für das Ende der Aktivität %
|
||||
%-------------------------------------------------------------------------------%
|
||||
% Siehe: https://www-kseta.ttp.kit.edu/fellows/Tanja.Harbaum/tikz_tutorial.pdf %
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
\tikzset{start/.style={circle,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
|
||||
\tikzset{activity/.style={rectangle,minimum width=1cm,minimum height=0.5cm,rounded corners=5pt,draw,align=center}}
|
||||
\tikzset{actBox/.style={rectangle,minimum width=1cm,minimum height=0.5cm,draw,align=center}}
|
||||
\tikzset{decision/.style={diamond,minimum width=1cm,minimum height=1cm,draw,align=center}}
|
||||
\tikzset{end/.style={draw,double=white,circle,inner sep=1pt,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
|
||||
|
||||
% Nodes und deren Position (voneinander abhängig) angeben
|
||||
\node[start] (Start) {};
|
||||
\node[activity, right = of Start] (Aufruf) {Website aufrufen};
|
||||
\node[actBox, right = of Aufruf] (Login1) {Login page};
|
||||
\node[activity, below = of Login1] (RegOpt) {\string"Registrieren\string"-Option\\ auswählen};
|
||||
\node[actBox, below = of RegOpt] (Registrieren) {Registrierungsfenster};
|
||||
\node[decision, below = of Registrieren] (EmailTakenEnd) {};
|
||||
\node[activity, below = of EmailTakenEnd] (Input) {E-Mail-Adresse und\\ zweimal neues\\ Passwort eingeben};
|
||||
\node[activity, below = of Input] (RegPress) {\string"Registrieren\string"-Button\\ drücken};
|
||||
\node[decision, left = of RegPress] (EmailTaken) {E-Mail\\ vergeben?};
|
||||
\node[actBox] (Error1) at (EmailTaken |- EmailTakenEnd) {Fehlermeldung};
|
||||
\node[actBox, below = of EmailTaken] (Confirm) {E-Mail mit Link\\ zur Verifizierung};
|
||||
\node[activity, below = of Confirm] (LinkClick) {Link\\ anklicken};
|
||||
\node[decision, right = of LinkClick] (LinkTime) {Link älter\\ als 24h?};
|
||||
\node[actBox, right = 2cm of LinkTime] (Error2) {Fehler};
|
||||
\node[actBox, below = 1.5cm of LinkTime] (Login2) {Login Page};
|
||||
\node[end] (End) at (Error2 |- Login2) {};
|
||||
\draw ($(Start.north west)+(-2,2)$) rectangle ($(End.south east)+(2,-1)$);
|
||||
\path ($(Start.north west)+(-2,1.4)$) -- ($(Start -| Error2)+(2,1.4)$) node[midway]{\Large \textbf{Registrieren}};
|
||||
|
||||
% Verbindungen zwischen den Nodes
|
||||
\draw[-stealth, thick](Start) -- (Aufruf);
|
||||
\draw[-stealth, thick](Aufruf) -- (Login1);
|
||||
\draw[-stealth, thick](Login1) -- (RegOpt);
|
||||
\draw[-stealth, thick](RegOpt) -- (Registrieren);
|
||||
\draw[-stealth, thick](Registrieren) -- (EmailTakenEnd);
|
||||
\draw[-stealth, thick](EmailTakenEnd) -- (Input);
|
||||
\draw[-stealth, thick](Input) -- (RegPress);
|
||||
\draw[-stealth, thick](RegPress) -- (EmailTaken);
|
||||
\draw[-stealth, thick](EmailTaken) -- node[left, near start]{ja} (Error1);
|
||||
\draw[-stealth, thick](Error1) -- (EmailTakenEnd);
|
||||
\draw[-stealth, thick](EmailTaken) -- node[left, near start]{nein} (Confirm);
|
||||
\draw[-stealth, thick](Confirm) -- (LinkClick);
|
||||
\draw[-stealth, thick](LinkClick) -- (LinkTime);
|
||||
\draw[-stealth, thick](LinkTime) -- node[above, near start]{ja} (Error2);
|
||||
\draw[-stealth, thick](LinkTime) -- node[left, near start]{nein} (Login2);
|
||||
\draw[-stealth, thick](Error2) -- (End);
|
||||
\draw[-stealth, thick](Login2) -- (End);
|
||||
|
||||
\end{tikzpicture}
|
70
00-pflichtenheft/sections/TikzPictures/ActivityResetPass.tex
Normal file
|
@ -0,0 +1,70 @@
|
|||
\begin{tikzpicture}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Nodeklassen für Aktivitätsdiagramm festlegen: %
|
||||
%-------------------------------------------------------------------------------%
|
||||
% start - Schwarzer ausgefüllter Kreis %
|
||||
% activity - Abgerundetes Rechteck für Aktivitäten des Users %
|
||||
% actBox - Rechteck für Reaktionen des Systems %
|
||||
% decision - Karokästchen für Entscheidungen / Abzweigungen %
|
||||
% end - Zielscheibe für das Ende der Aktivität %
|
||||
%-------------------------------------------------------------------------------%
|
||||
% Siehe: https://www-kseta.ttp.kit.edu/fellows/Tanja.Harbaum/tikz_tutorial.pdf %
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
\tikzset{start/.style={circle,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
|
||||
\tikzset{activity/.style={rectangle,minimum width=1cm,minimum height=0.5cm,rounded corners=5pt,draw,align=center}}
|
||||
\tikzset{actBox/.style={rectangle,minimum width=1cm,minimum height=0.5cm,draw,align=center}}
|
||||
\tikzset{decision/.style={diamond,minimum width=1cm,minimum height=1cm,draw,align=center}}
|
||||
\tikzset{end/.style={draw,double=white,circle,inner sep=1pt,minimum width=0.3cm,minimum height=0.3cm,draw,fill}}
|
||||
|
||||
% Nodes und deren Position (voneinander abhängig) angeben
|
||||
\node[start] (Start) {};
|
||||
\node[activity, right = of Start] (Aufruf) {Website aufrufen};
|
||||
\node[actBox, right = of Aufruf] (Login1) {Login page};
|
||||
\node[activity, below = of Login1] (ForgetOpt) {\string"Passwort vergessen\string"\\ Option auswählen};
|
||||
\node[actBox, below = of ForgetOpt] (Forget) {\string"Passwort vergessen\string"\\ Fenster};
|
||||
\node[decision, below = of Forget] (EmailDecEnd) {};
|
||||
\node[activity, below = of EmailDecEnd] (Input1) {E-Mail-Adresse\\ eingeben};
|
||||
\node[decision, left = of Input1] (EmailDec) {E-Mail\\ registriert?};
|
||||
\path (EmailDec) |- (EmailDecEnd) node[actBox, near end](Error2){Fehler};
|
||||
\node[actBox, below = of EmailDec] (SendMail) {E-Mail mit Link\\ zum Zurücksetzen\\ des Passworts};
|
||||
\node[activity, below = of SendMail] (LinkClick) {Empfangenen Link\\ öffnen};
|
||||
\node[decision, right = of LinkClick] (LinkTime) {Link älter\\ als 24h?};
|
||||
\node[actBox, above = of LinkTime] (Error) {Fehler};
|
||||
\node[end, right = of Error] (End1) {};
|
||||
\node[actBox, below = of LinkTime] (ResetWin) {\string"Passwort zurücksetzen\string"\\ Fenster};
|
||||
\node[decision, left = of ResetWin] (PswCorEnd) {};
|
||||
\node[activity, left = of PswCorEnd] (Input2) {neues Passwort\\ zweimal eingeben};
|
||||
\node[activity, below = 2cm of Input2] (ResetPress) {\string"Passwort zurücksetzen\string"-\\ Button drücken};
|
||||
\node[decision, right = of ResetPress] (PswCorrect) {Passwort\\ legal?};
|
||||
\node[actBox, right = of PswCorrect] (Login2) {Login page};
|
||||
\node[end, right = of Login2] (End2) {};
|
||||
\draw ($(Start.north west)+(-3,2)$) rectangle ($(End2.south east)+(1,-2)$);
|
||||
\path ($(Start.north west)+(-3,1.4)$) -- ($(Start -| End2)+(1,1.4)$) node[midway]{\Large \textbf{Passwort vergessen}};
|
||||
|
||||
% Verbindungen zwischen den Nodes
|
||||
\draw[-stealth, thick](Start) -- (Aufruf);
|
||||
\draw[-stealth, thick](Aufruf) -- (Login1);
|
||||
\draw[-stealth, thick](Login1) -- (ForgetOpt);
|
||||
\draw[-stealth, thick](ForgetOpt) -- (Forget);
|
||||
\draw[-stealth, thick](Forget) -- (EmailDecEnd);
|
||||
\draw[-stealth, thick](EmailDecEnd) -- (Input1);
|
||||
\draw[-stealth, thick](Input1) -- (EmailDec);
|
||||
\draw[-stealth, thick](EmailDec) |- node[left, near start]{nein} (Error2);
|
||||
\draw[-stealth, thick](Error2) -- (EmailDecEnd);
|
||||
\draw[-stealth, thick](EmailDec) -- node[left, near start]{ja} (SendMail);
|
||||
\draw[-stealth, thick](SendMail) -- (LinkClick);
|
||||
\draw[-stealth, thick](LinkClick) -- (LinkTime);
|
||||
\draw[-stealth, thick](LinkTime) -- node[left, near start]{ja} (Error);
|
||||
\draw[-stealth, thick](Error) -- (End1);
|
||||
\draw[-stealth, thick](LinkTime) -- node[left, near start]{nein} (ResetWin);
|
||||
\draw[-stealth, thick](ResetWin) -- (PswCorEnd);
|
||||
\draw[-stealth, thick](PswCorEnd) -- (Input2);
|
||||
\draw[-stealth, thick](Input2) -- (ResetPress);
|
||||
\draw[-stealth, thick](ResetPress) -- (PswCorrect);
|
||||
\draw[-stealth, thick](PswCorrect.north west) -| (PswCorEnd) node[above, near start]{nein};
|
||||
\draw[-stealth, thick](PswCorrect) -- (Login2) node[above, near start]{ja};
|
||||
\draw[-stealth, thick](Login2) -- (End2);
|
||||
|
||||
\end{tikzpicture}
|
|
@ -0,0 +1,79 @@
|
|||
%\begin{tikzpicture}
|
||||
%
|
||||
% \begin{umlseqdiag}
|
||||
%
|
||||
% \umlactor[no ddots]{Benutzer}
|
||||
% \umlobject[no ddots]{Podcatcher1}
|
||||
% \umlobject[no ddots]{Podcatcher2}
|
||||
% \umlobject[no ddots]{Webfrontend}
|
||||
% \umlobject[no ddots]{Server}
|
||||
%
|
||||
% \begin{umlcall}[dt=5, op=abonniere Podcast]{Benutzer}{Podcatcher1}
|
||||
% \begin{umlcallself}[dt=8, op=füge Podcast zu Abos hinzu, type=synchron]{Podcatcher1}
|
||||
% \end{umlcallself}
|
||||
% \begin{umlcall}[op=lade Änderungen hoch]{Podcatcher1}{Server}
|
||||
% \begin{umlcallself}[dt=8, op=speichere Änderungen]{Server}
|
||||
% \end{umlcallself}
|
||||
% \end{umlcall}
|
||||
% \end{umlcall}
|
||||
%
|
||||
% \begin{umlcall}[dt=10, op=Abos anzeigen]{Benutzer}{Webfrontend}
|
||||
% \begin{umlcall}[dt=5, op=hole Aboliste, return=Aboliste]{Webfrontend}{Server}
|
||||
% \end{umlcall}
|
||||
% \end{umlcall}
|
||||
%
|
||||
% \begin{umlcall}[dt=10, op=Abos anzeigen]{Benutzer}{Podcatcher2}
|
||||
% \begin{umlcall}[dt=5, op=hole Aboliste, return=Aboliste]{Podcatcher2}{Server}
|
||||
% \end{umlcall}
|
||||
% \end{umlcall}
|
||||
%
|
||||
% \end{umlseqdiag}
|
||||
%
|
||||
%\end{tikzpicture}
|
||||
|
||||
\begin{sequencediagram}
|
||||
|
||||
\newthread{b}{Benutzer}
|
||||
\newinst[2]{p1}{Podcatcher1}
|
||||
\newinst{p2}{Podcatcher2}
|
||||
\newinst[1]{w}{Webfrontend}
|
||||
\newinst[1]{s}{Server}
|
||||
|
||||
\begin{call}{b}{abonniere Podcast}{p1}{}
|
||||
\begin{callself}{p1}{füge Podcasts zu Abos hinzu}{}
|
||||
\begin{call}{p1}{lade Änderungen hoch}{s}{}
|
||||
\begin{callself}{s}{\shortstack{speichere\\Änderungen\\persistent}}{}
|
||||
\end{callself}
|
||||
\end{call}
|
||||
\end{callself}
|
||||
\end{call}
|
||||
|
||||
\begin{call}{b}{Abos anzeigen}{w}{}
|
||||
\begin{call}{w}{hole Aboliste}{s}{Aboliste}
|
||||
\end{call}
|
||||
\end{call}
|
||||
|
||||
\begin{call}{b}{Abos anzeigen}{p2}{}
|
||||
\begin{call}{p2}{hole Aboliste}{s}{Aboliste}
|
||||
\end{call}
|
||||
\end{call}
|
||||
|
||||
\end{sequencediagram}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
46
00-pflichtenheft/sections/TikzPictures/UseCaseUML.tex
Normal file
|
@ -0,0 +1,46 @@
|
|||
\begin{tikzpicture}%[trim left = 1cm]
|
||||
|
||||
\begin{umlsystem}[x=5] {<<Website>> Podcast Sync Web}
|
||||
\umlusecase[name=a,width=2.5cm] {Registrieren}
|
||||
\umlusecase[name=c,y=-4,width=2.5cm] {Aktion ausführen}
|
||||
\umlusecase[name=d,y=-6,width=2.5cm] {Anmelden}
|
||||
\umlusecase[name=f,y=-2,width=2.5cm] {Sprache ändern (*)}
|
||||
\umlusecase[name=g,x=6,y=-1,width=2.5cm] {Anleitung einsehen}
|
||||
\umlusecase[name=h,x=6,y=-3,width=2.5cm] {Abonnierte Podcasts einsehen}
|
||||
\umlusecase[name=i,x=6,y=-5,width=2.5cm] {Profil verwalten}
|
||||
\umlusecase[name=r,x=6,y=-7.25,width=2.5cm] {Zuletzt angehörte\\ Episoden einsehen}
|
||||
\umlusecase[name=j,x=6,y=-10.5,width=2.5cm] {Mit Google / anderen Anbietern anmelden (*)}
|
||||
\umlusecase[name=k,x=4,y=-13,width=2.5cm] {Passwort vergessen}
|
||||
\umlusecase[name=l,y=-15,width=2.5cm] {Admin Aktion ausführen (*)}
|
||||
\umlusecase[name=m,x=8,y=-15,width=2.5cm] {Statistiken einsehen (*)}
|
||||
\umlusecase[name=n,x=12,y=-4,width=2.5cm] {Passwort ändern}
|
||||
\umlusecase[name=o,x=12,y=-2,width=2.5cm] {Gpodder verknüpfen (*)}
|
||||
\umlusecase[name=p,x=12,y=-6,width=2.5cm] {Personenbezogene Daten abrufen (*)}
|
||||
\umlusecase[name=q,x=12,y=-8,width=2.5cm] {Account löschen}
|
||||
\end{umlsystem}
|
||||
|
||||
\umlactor[y=-3] {User}
|
||||
\umlactor[y=-15] {Admin}
|
||||
|
||||
\umlinherit{Admin}{User}
|
||||
|
||||
\umlassoc{User}{a}
|
||||
\umlassoc{User}{c}
|
||||
\umlassoc{User}{d}
|
||||
\umlassoc{User}{f}
|
||||
\umlassoc{Admin}{l}
|
||||
|
||||
\umlextend{g}{c}
|
||||
\umlextend{h}{c}
|
||||
\umlextend{i}{c}
|
||||
\umlextend{r}{c}
|
||||
\umlextend{j}{d}
|
||||
\umlextend{k}{d}
|
||||
\umlextend{m}{l}
|
||||
\umlinclude{c}{d}
|
||||
\umlinclude{l}{d}
|
||||
\umlextend{n}{i}
|
||||
\umlextend{o}{i}
|
||||
\umlextend{p}{i}
|
||||
\umlextend{q}{i}
|
||||
\end{tikzpicture}
|
219
00-pflichtenheft/sections/anforderungsanalyse.tex
Normal file
|
@ -0,0 +1,219 @@
|
|||
\newcommand{\newrequirementlist}[1]{
|
||||
% https://www.overleaf.com/learn/latex/Lists#Creating_a_new_list_with_enumitem
|
||||
\newlist{#1list}{enumerate}{1}
|
||||
\setlist[#1list, 1]
|
||||
{
|
||||
before=\leavevmode,
|
||||
label=\upshape\textlangle #1\arabic*\textrangle,
|
||||
ref=\upshape\textlangle #1\arabic*\textrangle,
|
||||
resume=#1list
|
||||
}
|
||||
}
|
||||
|
||||
\newrequirementlist{RM}
|
||||
\newrequirementlist{RS}
|
||||
\newrequirementlist{RC}
|
||||
\newrequirementlist{RW}
|
||||
|
||||
\section{Anforderungsanalyse}
|
||||
|
||||
\subsection{ Musskriterien }
|
||||
|
||||
Musskriterien: unabdingbare Leistungen der Software.
|
||||
|
||||
\subsubsection*{ Funktionale Anforderungen }
|
||||
|
||||
\begin{RMlist}
|
||||
\item\label{r:login} Der Benutzer kann sich im Webfrontend mit einer
|
||||
E-Mail-Adresse und einem Pass\-wort erstmalig registrieren und bei
|
||||
abgeschlossener Registrierung fortan mit denselben Informationen
|
||||
anmelden.
|
||||
Für eine erfolgreiche Registrierung muss die angegebene
|
||||
E-Mail-Adresse zuerst verifiziert werden.\\
|
||||
\emph{Tests: \ref{t:register}, \ref{t:login}}
|
||||
\item\label{r:store} Die Liste der \Glspl{abo} eines Benutzers sowie
|
||||
der zeitliche Fortschritt beim Anhören(/Ansehen) von jeder begonnen
|
||||
\Gls{episode} werden für jeden Benutzer gespeichert.
|
||||
\item\label{r:sync} Die Liste der \Glspl{abo} eines Benutzers
|
||||
sowie der zeitliche Fortschritt beim Anhören(/Ansehen) von jeder
|
||||
begonnenen \Gls{episode} wird automatisch über alle von einem Benutzer
|
||||
verknüpften \Gls{podcatcher}n aktualisiert.
|
||||
Dabei sind der zu synchronisierende Stand der \Glspl{abo} und der
|
||||
zeitliche Fortschritt jeweils definiert als derjenige Stand, der
|
||||
zeitlich am kürzesten zurückliegt.\\
|
||||
\emph{Tests: \ref{t:sync-sub}, \ref{t:sync-unsub}, \ref{t:sync-episode}}
|
||||
\item\label{r:ui} Das Webfrontend bietet dem Benutzer eine graphische
|
||||
Benutzeroberfläche zur Navigation und zur Ansteuerung einzelner
|
||||
Funktionalitäten.\\
|
||||
\emph{Implizit durch alle Testfälle geprüft.}
|
||||
\item\label{r:reset-pw} Der Benutzer kann sein Passwort ändern und es
|
||||
gibt eine ,,Passwort vergessen''-Funktion.
|
||||
So kann ein angemeldeter Benutzer sein Passwort direkt im Webfrontend
|
||||
ändern.
|
||||
Im nicht angemeldeten Zustand kann der Benutzer sein Passwort über
|
||||
die registrierte E-Mail-Adresse zurücksetzen.\\
|
||||
\emph{Tests: \ref{t:change-pw}, \ref{t:forgot-pw}}
|
||||
\item\label{r:show-podcasts} Das Webfrontend bietet dem Benutzer die
|
||||
Möglichkeit, sich die Liste seiner \Glspl{abo} anzeigen zu
|
||||
lassen.
|
||||
Die dabei dargestellten Informationen beinhalten den Namen des
|
||||
\Glspl{abo} und eine gerundete Angabe darüber, wie lange es her ist,
|
||||
dass der Benutzer das letzte Mal eine \Gls{episode} dieses \Glspl{abo}
|
||||
konsumiert hat.\\
|
||||
\emph{Tests: \ref{t:sync-sub}, \ref{t:sync-unsub}}
|
||||
\end{RMlist}
|
||||
|
||||
\subsubsection*{ Nicht-funktionale Anforderungen }
|
||||
|
||||
\begin{RMlist}
|
||||
\item\label{r:requests} Der Synchronisations-Server kann mindestens
|
||||
50 Anfragen pro Sekunde verarbeiten.\\
|
||||
\emph{Test: \ref{t:lasttest}}
|
||||
\item\label{r:desktop-first} Das Webfrontend ist primär für
|
||||
Desktop-Benutzer ausgelegt.
|
||||
\item\label{r:gpodder} Der Datenaustausch erfolgt über die Gpodder
|
||||
\Gls{rest-api} unter Verwendung des Datenformats \Gls{json}.
|
||||
\item\label{r:persistent-storage} Die Speicherung der Daten eines
|
||||
Benutzers \ref{r:store} über den Synchronisations-Server erfolgt
|
||||
persistent in einer \Gls{db}. Diese Daten des Benutzers sind die
|
||||
Liste seiner \Glspl{abo} und der zeitliche Fortschritt beim Anhören
|
||||
(/Ansehen) aller begonnenen \Glspl{episode}.
|
||||
\item\label{r:api-extension} Die \Gls{gpodder} wird um Funktionalitäten
|
||||
zur verbesserten Kommunikation zwischen Front- und Backend erweitert
|
||||
(siehe \ref{r:login}).\\
|
||||
\end{RMlist}
|
||||
|
||||
|
||||
\subsection{ Sollkriterien }
|
||||
|
||||
Sollkriterien: erstrebenswerte Leistungen.
|
||||
|
||||
\subsubsection*{ Funktionale Anforderungen }
|
||||
|
||||
\begin{RSlist}
|
||||
\item\label{r:man} Das Webfrontend bietet die Möglichkeit eine nicht
|
||||
ausgefüllte Benutzeranleitung für das Synchronisieren von \Glspl{podcast}
|
||||
anzuzeigen (Abbildung \ref{fig:help-desktop}).\\
|
||||
\emph{Test: \ref{t:man}}
|
||||
\item\label{r:delete-acc} Der Benutzer kann seinen Account löschen.
|
||||
Daraufhin werden alle auf diesen Benutzer bezogenen Daten gelöscht.\\
|
||||
\emph{Test: \ref{t:delete-acc}}
|
||||
\end{RSlist}
|
||||
|
||||
\subsubsection*{ Nicht-funktionale Anforderungen }
|
||||
|
||||
\begin{RSlist}
|
||||
\item\label{r:backend-libs} Das Backend wird in \Gls{java} unter Verwendung des
|
||||
quelloffenen Frameworks Spring implementiert. Weiter wird für die
|
||||
\Gls{db} das relationale Open-Source Datenbankverwaltungssystem MariaDB
|
||||
eingesetzt.
|
||||
\item\label{r:ui-libs} Die Weboberfläche wird mithilfe der
|
||||
\Gls{ui-lib} React oder des Webframeworks Vue in JavaScript und
|
||||
mit dem Frontend-CSS-Framework Bootstrap entwickelt.
|
||||
\item\label{r:ui-source}
|
||||
Verwendete \Glspl{ui-lib} werden von einem \Gls{packagemanager}, wie dem Node
|
||||
Package Manager (npm) bezogen. Ein \Gls{bundler}, wie vite oder Webpack,
|
||||
stellt ein minimiertes Skript von den Teilen der Bibliotheken zusammen,
|
||||
die vom Code verwendet werden. Das minimierte Skript wird dann auf einem
|
||||
eigenen Server für die Weboberfläche bereitgestellt.
|
||||
\item\label{r:spa} Die Weboberfläche wird als \Gls{spa}
|
||||
entworfen und aktualisiert dynamisch ihren Inhalt, sobald es eine
|
||||
Antwort auf eine Anfrage an die \Gls{gpodder} \ref{r:api-compat} erhält.
|
||||
\item\label{r:parse-metadata} Das Backend kann die Metadaten von
|
||||
\Gls{podcast} aus
|
||||
deren \Gls{rss}-Feeds (XML-Dateien) für die Anzeige im Webfrontend
|
||||
\ref{r:show-podcasts} parsen.
|
||||
\item\label{r:pw-requirements} Verwendete Passwörter müssen mindestens 8 Zeichen,
|
||||
ein Sonderzeichen, eine Zahl sowie einen Klein- und einen Großbuchstaben
|
||||
enthalten.
|
||||
Diese Anforderungen gelten also insbesondere für über die Funktionen
|
||||
\ref{r:login} und \ref{r:reset-pw} neu gewählte Passwörter.\\
|
||||
\emph{Test: \ref{t:pw-req}}
|
||||
\item\label{r:save-pw} Passwörter werden sicher mittels \Gls{salt-hash}
|
||||
gespeichert.
|
||||
\item\label{r:session} Im Webfrontend angemeldete Benutzer bleiben dort
|
||||
angemeldet. Hierfür wird ein \Gls{session-token} in einem \Gls{cookie} gespeichert.\\
|
||||
\end{RSlist}
|
||||
|
||||
\subsection{ Kannkriterien }
|
||||
|
||||
Kannkriterien: Leistungen, die enthalten sein können.
|
||||
|
||||
\subsubsection*{ Funktionale Anforderungen }
|
||||
|
||||
\begin{RClist}
|
||||
\item\label{r:subscribe} Ein Benutzer kann über die Weboberfläche einen
|
||||
abonnierten \Gls{podcast} über einen generierten Link teilen.
|
||||
Öffnet nun ein anderer Nutzer den Link wird dieser zur Weboberfläche
|
||||
weitergeleitet und mit einem Pop-up gefragt, ob dieser den
|
||||
\Gls{podcast} abonnieren
|
||||
möchte, falls noch nicht geschehen.
|
||||
Akzeptiert der Nutzer, so wird der \Gls{podcast} zur Liste der
|
||||
\Glspl{abo} des
|
||||
Nutzers hinzugefügt.
|
||||
Gegebenenfalls muss sich der Benutzer dafür zuerst anmelden.
|
||||
Der Link setzt sich dabei unter anderem aus der URL des Webfrontends oder
|
||||
einem \Gls{pseudoprotocol} und dem \Gls{podcast}-Link des Providers zusammen.
|
||||
\item\label{r:unsubscribe} Das Webfrontend bietet dem Benutzer die Möglichkeit,
|
||||
\Glspl{abo} zu entfernen beziehungsweise \Glspl{podcast} zu deabonnieren.
|
||||
\item\label{r:import} Das Importieren und Exportieren aller benutzerbezogenen
|
||||
Daten wird unterstützt (siehe \ref{r:dsgvo}).
|
||||
\item\label{r:import-other} Das Umsiedeln von anderen Gpodder-Plattformen und
|
||||
damit insbesondere der damit verbundene Datenimport wird unterstützt.
|
||||
\item\label{r:api-compat} Die Weboberfläche ist kompatibel mit beliebigen
|
||||
\Glspl{gpodder}.
|
||||
\item\label{r:responsive} Die Weboberfläche ist \gls{responsive}.
|
||||
\item\label{r:admin} Es gibt Administrator Benutzerkonten. Eine angestrebte
|
||||
Funktionalität dieser privilegierten Konten ist das Einsehen von Statistiken,
|
||||
wie der Anzahl von Benutzern, und dem Abruf der Metadaten eines
|
||||
\Glspl{abo}.
|
||||
\end{RClist}
|
||||
|
||||
\subsubsection*{ Nicht-funktionale Anforderungen }
|
||||
|
||||
\begin{RClist}
|
||||
\item\label{r:login-provider} Die Anmeldung im Webfrontend kann mit dem
|
||||
offenen Protokoll \Gls{oauth} 2.0 über Google, Apple oder Facebook erfolgen.
|
||||
Die bei der Verknüpfung eines \Gls{podcatcher}s mit dem Synchronisationsserver
|
||||
geforderten Anmeldedaten werden dann automatisch für den betreffenden
|
||||
Benutzer generiert.
|
||||
Diese kann er im Webfrontend einsehen.
|
||||
\item\label{r:live-update} Im Webfrontend angemeldete Benutzer bleiben dort
|
||||
angemeldet, wenn das Backend ein Update bekommt.
|
||||
\item\label{r:language} Die Benutzeroberfläche kann in mehreren Sprachen
|
||||
angezeigt werden, wobei neben der standardmäßig deutschen
|
||||
Benutzeroberfläche die zusätzliche Bereitstellung einer englischen
|
||||
Version gegenüber anderen Fremdsprachen priorisiert angestrebt wird.
|
||||
\item\label{r:dsgvo} Der Umgang mit personenbezogenen Daten ist konform mit
|
||||
der \\\Gls{dsgvo} der Europäischen Union.
|
||||
\item\label{r:docker} Die Benutzung von \Gls{docker} vereinfacht das Deployment auf
|
||||
einen Server, da Abhängigkeiten bereits im \Gls{docker}-Image enthalten sind.
|
||||
Außerdem bleibt bei einer Kompromittierung der Software das Host-System
|
||||
durch Virtualisierung der Container sicher.\\
|
||||
\end{RClist}
|
||||
|
||||
\subsection{ Abgrenzungskriterien }
|
||||
|
||||
Abgrenzungskriterien: Leistungen, die explizit nicht umgesetzt werden.
|
||||
|
||||
\begin{RWlist}
|
||||
\item\label{r:playback} Das Webfrontend stellt explizit keine Funktionalität
|
||||
zum Anhören von \Glspl{podcast} bereit und grenzt sich unter anderem dadurch
|
||||
von \Gls{podcatcher}-Software ab.
|
||||
\item\label{r:no-logs} Es werden explizit keine Logdateien für Benutzer-Aktionen
|
||||
gespeichert. Stattdessen wird nur genau die Liste der \Glspl{abo} eines
|
||||
Benutzers und der zeitliche Fortschritt jeder \Gls{episode} aktuell gehalten.
|
||||
\item\label{r:no-devices} Die benutzerdefinierte Synchronisation über
|
||||
verschiedene, für die Synchronisation differenzierte Geräte wird nicht
|
||||
unterstützt.
|
||||
Das heißt, die gespeicherten Daten eines Benutzers werden über alle
|
||||
mit seinem Account verbundenen \Gls{podcatcher} unabhängig vom Gerät auf den
|
||||
gleichen, letzten Stand synchronisiert.
|
||||
\item\label{r:discovery} Das Webfrontend bietet keine Funktionalität zum
|
||||
Suchen von \Glspl{podcast} (\Gls{discovery}) an.
|
||||
\item\label{r:no-man} Im Webfrontend wird lediglich die Möglichkeit geboten,
|
||||
eine zunächst leere Benutzeranleitung \ref{r:man} anzuzeigen. Eine
|
||||
inhaltlich vollständig ausgeschriebene Benutzeranleitung wird
|
||||
ausdrücklich nicht bereitgestellt.
|
||||
\end{RWlist}
|
||||
|
183
00-pflichtenheft/sections/benutzeroberflaeche.tex
Normal file
|
@ -0,0 +1,183 @@
|
|||
\section{Benutzeroberfläche}
|
||||
|
||||
Die Synchronisation der \Glspl{podcast} soll über eine Weboberfläche verwalten werden.
|
||||
Dazu wird eine \Gls{spa} erstellt. Diese kann durch ein
|
||||
\Gls{responsive}-Design für Desktop- und Mobilgeräte nutzerfreundlich angezeigt
|
||||
werden.
|
||||
|
||||
Die Navigation erfolgt über eine Navigationsleiste, welche auf jeder
|
||||
nutzerbezogenen Seite zu sehen ist. Über die Navigationsleiste können über
|
||||
Knöpfe alle anderen nutzerbezogenen Seiten aufgerufen werden. Über ein
|
||||
Dropdown-Menu werden Accounteinstellungen und ein Logout-Knopf sichtbar (siehe
|
||||
Abbildung \ref{fig:listening-progress-account-dropdown}). Ein weiters
|
||||
Dropdown-Menu erlaubt das Wechseln der Sprache (siehe Abbildung
|
||||
\ref{fig:podcast-desktop-change-language}). Der ,,Hilfe''-Eintrag öffnet ein
|
||||
Fenster mit Hilfestellungen (siehe Abbildung \ref{fig:help-desktop}). Durch das
|
||||
\Gls{responsive}-Design kann die Navigations-Leiste auf Mobilgeräten sich zu
|
||||
einem Burger-Menu zusammenklappen.
|
||||
|
||||
Die Komponenten der Weboberfläche werden von einem Still-Framework, wie Bootstrap,
|
||||
benutzt.
|
||||
|
||||
% Übersichtlichkeit wichtig?
|
||||
|
||||
% Webanwendung
|
||||
% Single-Page-Application
|
||||
% Responsive
|
||||
% Navigationsleiste
|
||||
% Bootstrap
|
||||
|
||||
\subsection{Login}
|
||||
|
||||
Bei der erstmaligen Nutzung des Services wird der Nutzer aufgefordert, sich neu
|
||||
für die \Gls{podcast}-Synchronisation zu registrieren. Dabei gibt der Nutzer seine
|
||||
E-Mail und ein Passwort ein. Daraufhin wird dem Nutzer eine E-Mail mit einem
|
||||
Bestätigungslink an seine E-Mail-Adresse versandt. Erst wenn der Link angeklickt
|
||||
wird, ist der Account freigeschaltet und der Nutzer wird zur Anmeldeseite
|
||||
weitergeleitet (siehe Abbildung \ref{fig:login-mobile}).
|
||||
|
||||
Alternativ kann der Nutzer sich auch mit einem Identifikationsbereitsteller, wie
|
||||
Google oder Facebook registrieren und anmelden.
|
||||
|
||||
Zusätzlich kann der Nutzer beim Anmelden über eine Checkbox einstellen, dass
|
||||
dieser angemeldet bleiben möchte, sodass sich dieser beim nächsten Aufruf der
|
||||
Weboberfläche nicht erneut anmelden muss.
|
||||
|
||||
Nach dem Anmelden wird der Nutzer zur \Gls{podcast}-Liste weitergeleitet.
|
||||
|
||||
% Registrieren
|
||||
% E-Mail und Passwort, E-Mail bestätigung
|
||||
|
||||
% anmelden mit E-Mail und Passwort oder es kann sich auch mit einem
|
||||
% Identifikations-Bereitsteller (wie Google, Facebook, GitHub) angemeldet
|
||||
% werden.
|
||||
|
||||
% Angemeldet bleiben
|
||||
|
||||
% Anschließlich auf der Startseite
|
||||
|
||||
\subsection{Podcast-Liste}
|
||||
|
||||
Die Seite der \Gls{podcast}-Liste zeigt eine Liste aller vom Nutzer abonnierten
|
||||
\Glspl{podcast}. Diese sind danach sortiert, welcher \Gls{podcast} zuletzt
|
||||
gehört wurde (siehe Abbildung \ref{fig:podcast-desktop-change-language}).
|
||||
|
||||
\Glspl{podcast} können aufgeklappt werden, um \Glspl{episode} inklusive deren Hörfortschritt
|
||||
anzuzeigen. Die \Glspl{episode} werden nach Veröffentlichungszeitpunkt sortiert.
|
||||
|
||||
% Navigatinsleiste
|
||||
% Zeigt eine Liste aller vom Nutzer abonnierten Podcasts sortiert nach welcher
|
||||
% Podcast zuletzt gehört wurde.
|
||||
% Podcasts können aufgeklappt werden, um Episoden inklusive deren Hörfortschritt
|
||||
% anzuzueigen. Die Episoden werden nach Veröffentlichungszeitpunkt sortiert.
|
||||
|
||||
\subsection{Zuletzt gehört}
|
||||
|
||||
Die Seite ,,Zuletzt gehört'' zeigt eine Liste der vom Nutzer gehörten
|
||||
\Glspl{episode} inklusive Hörfortschritt (siehe Abbildung
|
||||
\ref{fig:listening-progress-account-dropdown}). Die \Glspl{episode} sind danach
|
||||
sortiert wann sie zuletzt gehört wurden.
|
||||
|
||||
Zusätzlich können die beendeten und angefangenen \Glspl{episode} über ein
|
||||
Dropdown-Menu auch auf- und absteigend lexikografisch oder nach Hörfortschritt
|
||||
sortiert werden.
|
||||
|
||||
% \newpage
|
||||
|
||||
\subsection{Einstellungen}
|
||||
|
||||
Auf der Einstellungsseite darf der Nutzer sein Passwort ändern und seinen
|
||||
Account löschen (siehe Abbildung \ref{fig:settings-mobile-1}).
|
||||
|
||||
Der Nutzer kann seine personenbezogenen Daten, wie abonnierte \Glspl{podcast} und
|
||||
Hörfortschritte, in eine Datei exportieren, welche der Nutzer herunterladen
|
||||
kann. Außerdem kann der Nutzer zuvor heruntergeladene Exports wieder
|
||||
importieren, um zum Beispiel alte abonnierte \Glspl{podcast} wiederherzustellen.
|
||||
|
||||
Zusätzlich kann der Nutzer seine Daten von einer anderen \Gls{gpodder} importieren,
|
||||
indem er sich in den Einstellungen auf der anderen \Gls{gpodder} anmeldet.
|
||||
|
||||
% Passwort ändern
|
||||
% Account löschen
|
||||
% Daten importieren/exportieren
|
||||
% Daten anderer Gpodder-API importieren
|
||||
|
||||
% \vspace{1cm}
|
||||
|
||||
%===================================================================================%
|
||||
% https://tex.stackexchange.com/questions/55337/how-to-use-figure-inside-a-minipage %
|
||||
%===================================================================================%
|
||||
\hspace{-.5cm}
|
||||
\begin{minipage}[H]{\linewidth}
|
||||
%\centering
|
||||
\begin{minipage}{0.32\linewidth}
|
||||
\begin{figure}[H]
|
||||
\fbox{\includegraphics[width=.9\linewidth]{assets/ui/login-mobile.png}}
|
||||
\setcapindent*{1em}
|
||||
\caption{Anmeldeseite mit Identitätsbereitsteller\\}
|
||||
\label{fig:login-mobile}
|
||||
\end{figure}
|
||||
\end{minipage}
|
||||
% \hspace{0.05\linewidth}
|
||||
\begin{minipage}{0.32\linewidth}
|
||||
\begin{figure}[H]
|
||||
\fbox{\includegraphics[width=.9\linewidth]{assets/ui/podcasts-mobile.png}}
|
||||
\setcapindent*{1em}
|
||||
\caption{Mobile \Glspl{podcast}-Seite mit Burger-Menu\\}
|
||||
\label{fig:podcasts-mobile}
|
||||
\end{figure}
|
||||
\end{minipage}
|
||||
% \hspace{0.05\linewidth}
|
||||
\begin{minipage}{0.32\linewidth}
|
||||
\begin{figure}[H]
|
||||
\fbox{\includegraphics[width=.9\linewidth]{assets/ui/listening-progress-mobile.png}}
|
||||
\setcapindent*{1em}
|
||||
\caption{Mobile ,,Zuletzt gehört''-Seite mit offenem Burger-Menu}
|
||||
\label{fig:listening-progress-mobile}
|
||||
\end{figure}
|
||||
\end{minipage}
|
||||
\end{minipage}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\fbox{\includegraphics[width=.9\linewidth]{assets/ui/podcasts-desktop-change-language.png}}
|
||||
\caption{\Glspl{podcast}-Seite mit \Glspl{episode} und Sprachauswahl}
|
||||
\label{fig:podcast-desktop-change-language}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\fbox{\includegraphics[width=.9\linewidth]{assets/ui/listening-progess-account-dropdown.png}}
|
||||
\caption{,,Zuletzt gehört''-Seite mit Fortschrittsbalken und Account-Dropdown}
|
||||
\label{fig:listening-progress-account-dropdown}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=.87\linewidth]{assets/ui/help-desktop.png}
|
||||
\caption{Hilfe-Fenster, welches mit dem Menu-Eintrag ,,Hilfe'' geöffnet wird}
|
||||
\label{fig:help-desktop}
|
||||
\end{figure}
|
||||
|
||||
\begin{minipage}[H]{.9\linewidth}
|
||||
\centering
|
||||
\begin{minipage}{.4\linewidth}
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\fbox{\includegraphics[width=.8\linewidth]{assets/ui/settings-mobile-1.png}}
|
||||
\setcapindent*{1em}
|
||||
\caption{Einstellungen mit Ändern des Passworts und Gpodder-Verknüpfung}
|
||||
\label{fig:settings-mobile-1}
|
||||
\end{figure}%
|
||||
\end{minipage}
|
||||
\hspace{.5cm}
|
||||
\begin{minipage}{.4\linewidth}
|
||||
\begin{figure}[H]
|
||||
\fbox{\includegraphics[width=.8\linewidth]{assets/ui/settings-mobile-2.png}}
|
||||
\setcapindent*{1em}
|
||||
\caption{Einstellungen mit Datenexport und Accountlöschung\\}
|
||||
\label{fig:settings-mobile-2}
|
||||
\end{figure}
|
||||
\end{minipage}
|
||||
\end{minipage}
|
||||
|
34
00-pflichtenheft/sections/einleitung.tex
Normal file
|
@ -0,0 +1,34 @@
|
|||
\section{Einleitung}
|
||||
|
||||
Dieses Softwareprojekt setzt sich zum Ziel, einen im Vergleich zu anderen Synchronisationsservern
|
||||
möglichst schlanken und performanten Synchronisationsserver für \Glspl{podcast}
|
||||
bereitzustellen, welcher von sogenannten \Glspl{podcatcher} verwendet werden soll.
|
||||
|
||||
Ein \Gls{podcatcher} ist eine Anwendung, mit der \Glspl{podcast} abonniert,
|
||||
heruntergeladen und angehört werden können.
|
||||
Durch diesen Synchronisationsserver ermöglichen Betreiber von \Glspl{podcatcher} den Nutzern
|
||||
eine einfache Möglichkeit zum Synchronisieren von \Glspl{podcast} über verschiedene
|
||||
Geräte hinweg.
|
||||
Im Gegensatz zu anderen Synchronisationsservern für \Glspl{podcast} versucht dieses Produkt
|
||||
möglichst einfach und unkompliziert in der Handhabung zu sein. Deshalb wird nur eine
|
||||
grundlegende Synchronisationsfunktion ohne weitere
|
||||
Anpassungsmöglichkeit bereitgestellt.
|
||||
Außerden werden Funktionalitäten die bereits von einem \Gls{podcatcher} ermöglicht werden, wie
|
||||
zum Beispiel das Anhören und Verwalten von \Glspl{podcast}, nicht bereitgestellt.
|
||||
Dies sorgt zusätzlich für ein schlankes Backend.
|
||||
|
||||
Es werden hierbei sowohl die \Glspl{podcast} an sich, als auch die aktuellen
|
||||
Hörfortschritte synchronisiert.
|
||||
Das bedeutet, dass alle vorgenommenen Änderungen auf den Server gespiegelt
|
||||
werden.
|
||||
Die Änderungen werden danach von jedem mit dem Account verbundenen
|
||||
\Gls{podcatcher} heruntergeladen.
|
||||
Dazu werden die \Glspl{podcast} und die Hörfortschritte eines jeden Nutzers in einer
|
||||
\Gls{db} gespeichert.
|
||||
Auf die \Gls{db} können die \Gls{podcatcher} mit einer API in Verbindung eines
|
||||
Nutzeraccounts lesend und schreibend zugreifen.
|
||||
Um eine Kompatibilität mit bestehenden Podcatchern
|
||||
sicherzustellen, wird die weitverbreitete \Gls{gpodder} verwendet.
|
||||
Zusätzlich soll es Nutzern durch ein Webinterface ermöglicht werden, ihre
|
||||
synchronisierten \Glspl{podcast} einsehen zu können und ihren Nutzeraccount verwalten zu können.
|
||||
|
272
00-pflichtenheft/sections/glossar.tex
Normal file
|
@ -0,0 +1,272 @@
|
|||
\makeglossaries
|
||||
|
||||
\newglossaryentry{spa}
|
||||
{
|
||||
name=Single-Page-Application,
|
||||
description={
|
||||
ist ein Webseiten-Modell, bei welchem dem Nutzer nur ein Webdokument
|
||||
bereitgestellt wird. Mit einem Skript wird der Inhalt der Seite
|
||||
dynamisch mit Daten einer API befüllt. Außerdem verwaltet die Seite
|
||||
(nicht der Server), welcher Inhalt bei welchem Pfad angezeigt wird. Dies
|
||||
erzeugt geringere Serverlast und eine bessere Nutzererfahrung, da die
|
||||
Seitenstruktur beim Laden von neuen Inhalten erhalten bleibt}
|
||||
}
|
||||
|
||||
\newglossaryentry{packagemanager}
|
||||
{
|
||||
name=Paketmanager,
|
||||
description={
|
||||
ist ein Programm, welches Pakete und dessen Abhängigkeiten verwaltet,
|
||||
installiert, entfernt und aktualisiert. Pakete können andere Programme,
|
||||
Plugins oder Software-Bibliotheken sein}
|
||||
}
|
||||
|
||||
\newglossaryentry{bundler}
|
||||
{
|
||||
name=Bundler,
|
||||
description={
|
||||
ist ein Programm, welches genutzte Teile von Abhängigkeiten eines
|
||||
Software-Projekts in passender Reihenfolge zusammensucht und daraus
|
||||
Dateien erstellt, die für den Nutzer bereitgestellt werden können. Dabei
|
||||
kann der Bundler mit zusätzlichen Modulen Dateien erzeugen, die
|
||||
rückwärtskompatibel oder für den Nutzer schwerer einsehbar sind}
|
||||
}
|
||||
|
||||
\newglossaryentry{java}
|
||||
{
|
||||
name=Java,
|
||||
description={
|
||||
ist eine objekt-orientierte interpretierte kompilierte
|
||||
Programmiersprache, welche plattformunabhängig auf einer virtuellen
|
||||
Maschine ausgeführt wird}
|
||||
}
|
||||
|
||||
\newglossaryentry{db}
|
||||
{
|
||||
name=Datenbank,
|
||||
description={
|
||||
ist ein System um Daten persistent zu speichern und effizient zu
|
||||
verwalten. Am meisten verbreitet sind relationale Datenbanken, welche
|
||||
Daten in Tabellen mit Referenzen zu Einträgen anderer Tabellen
|
||||
speichern. Programme können dann über eine Anfragesprache (Structured
|
||||
Query Language - SQL) komplexe Operationen auf den Daten ausführen}
|
||||
}
|
||||
|
||||
\newglossaryentry{docker}
|
||||
{
|
||||
name=Docker,
|
||||
description={
|
||||
ist ein Programm, das virtualisierte Container ausführt. Ein Programm in
|
||||
so einem Container läuft in seiner eigenen virtuellen Umgebung, wodurch
|
||||
das Host-System sicher bleibt. Zudem lassen sich die Container leicht
|
||||
auf andere Systeme verteilen}
|
||||
}
|
||||
|
||||
% RESTfull-API, JSON, RSS-Feed, Salting and Hasing, OAuth, Cookie, Garbage
|
||||
% Collection, DSGVO, Podcast, Podcatcher, Episode, Gpodder,
|
||||
|
||||
\newglossaryentry{podcatcher}
|
||||
{
|
||||
name=Podcatcher,
|
||||
plural=Podcatchern,
|
||||
description={
|
||||
ist ein Programm, über welches man Podcasts entdecken, abonnieren und
|
||||
Episoden von Podcasts hören kann. Mit einem Account auf einer Plattform,
|
||||
welche eine Gpodder-API zur Verfügung stellt, können Ereignisse, die von
|
||||
einem Nutzer ausgehen, auf anderen Podcatchern des Nutzers
|
||||
synchronisiert werden}
|
||||
}
|
||||
|
||||
\newglossaryentry{podcast}
|
||||
{
|
||||
name=Podcast,
|
||||
description={
|
||||
ist ein RSS-Feed, dessen Einträge die Episoden darstellen}
|
||||
}
|
||||
|
||||
\newglossaryentry{episode}
|
||||
{
|
||||
name=Episode,
|
||||
plural=Episoden,
|
||||
description={
|
||||
ist ein Eintrag in einem Podcast. Eine URL in dem Eintrag zeigt auf eine
|
||||
Medien-Datei, welche vom Podcatcher abgespielt werden kann}
|
||||
}
|
||||
|
||||
\newglossaryentry{rest-api}
|
||||
{
|
||||
name=RESTful-API,
|
||||
description={
|
||||
ist ein Schnittstellenentwurf über das Hypertext Transfer Protocol
|
||||
(HTTP), bei dem die Schnittstellen strukturiert als Pfad an einem
|
||||
Endpunkt erreichbar sind. Mittels verschiedener HTTP-Methoden können an
|
||||
der Schnittstelle Daten abgefragt (GET), gesendet (PUT), gelöscht
|
||||
(DELETE) oder geändert (POST) werden. Die Daten, die über die
|
||||
Schnittstelle gesendet werden liegen meist im JSON-Format vor}
|
||||
}
|
||||
|
||||
|
||||
\newglossaryentry{gpodder}
|
||||
{
|
||||
name=Gpodder-API,
|
||||
description={
|
||||
wird von gpodder.net benutzt und entwickelt. Die API wird als
|
||||
Schnittstelle zwischen Podcatchern und Podcast Synchronisationsservern
|
||||
verwendet. Weitere Details sind unter
|
||||
"https://gpoddernet.readthedocs.io/en/latest/api/" zu finden}
|
||||
}
|
||||
|
||||
\newglossaryentry{json}
|
||||
{
|
||||
name=JSON,
|
||||
description={
|
||||
(JavaScript Object Notation) ist ein Datenformat und wird zur
|
||||
Übertragung von Strukturen und Daten eingesetzt. JSON besteht dabei aus
|
||||
grundlegenden Datentypen sowie Objekten mit Schlüssel-Wert Paaren und
|
||||
Listen}
|
||||
}
|
||||
|
||||
\newglossaryentry{oauth}
|
||||
{
|
||||
name=OAuth,
|
||||
description={
|
||||
(Open Authorization) ist ein offenes Protokoll, welches es Nutzern
|
||||
ermöglicht, sich mit bereits bestehenden Accounts bei anderen Diensten
|
||||
zu registrieren. Dabei werden benötigte Daten für die Registrierung über
|
||||
die bereitgestellte Schnittstelle zur Verfügung gestellt}
|
||||
}
|
||||
|
||||
\newglossaryentry{garbage-collection}
|
||||
{
|
||||
name=Garbage Collection,
|
||||
description={
|
||||
ist eine automatische Speicherbereinigung, welche nicht mehr benötigten
|
||||
Speicherplatz wieder freigibt. Die Bereinigung kann dabei in determinierten
|
||||
Zeitintervallen erfolgen oder durch bestimmte Ereignisse ausgelöst
|
||||
werden}
|
||||
}
|
||||
|
||||
\newglossaryentry{salt-hash}
|
||||
{
|
||||
name=Salting und Hashing,
|
||||
description={
|
||||
ist eine Methode um Passwörter so zu kodieren, dass sie nicht als
|
||||
Klartext gespeichert werden und auch sicher vor Hash-Wörterbüchern sind.
|
||||
Dafür wird dem Passwort ein bekanntes Wort, der Salt, angefügt, bevor
|
||||
aus dem kompletten Wort eine Prüfsumme, ein Hash, generiert wird. Beim
|
||||
Anmelden wird die Prüfsumme der Anmeldung mit der bekannten
|
||||
Prüfsumme des Passworts verglichen}
|
||||
}
|
||||
|
||||
\newglossaryentry{rss}
|
||||
{
|
||||
name=RSS,
|
||||
description={
|
||||
(Really Simple Syndication) zeigt strukturiert Listen von Nachrichten
|
||||
an. Die Änderungen werden im XML-Format in sogenannte RSS-Dateien
|
||||
geschrieben, welche über einen Link abgerufen werden können}
|
||||
}
|
||||
|
||||
\newglossaryentry{dsgvo}
|
||||
{
|
||||
name=Datenschutz-Grundverordnung,
|
||||
description={
|
||||
(DSGVO) ist eine im europäischen Wirtschaftsraum
|
||||
geltende Verordnung. Sie sorgt für eine Reglementierung bei der
|
||||
Verarbeitung personenbezogener Daten. Unter anderem muss einsehbar sein,
|
||||
welche Daten von Nutzern erhoben werden. Außerdem muss für einen Nutzer
|
||||
die Möglichkeit bestehen, seine erhobenen Daten abrufen zu können}
|
||||
}
|
||||
|
||||
\newglossaryentry{push-pull}
|
||||
{
|
||||
name=Push und Pull,
|
||||
description={
|
||||
sind Methoden, um Daten auszutauschen. Bei der Pull-Methode
|
||||
stellt Akteur A einem Akteur B eine Anfrage auf Daten und erhält diese
|
||||
als Antwort. Damit Akteur A und B immer auf dem selben Stand sind, muss
|
||||
Akteur A chronisch Anfragen an Akteur B stellen. Im Gegensatz dazu steht
|
||||
die Push-Methode, bei der Akteur B den Akteuren mitteilt, dass er neue
|
||||
Änderungen hat. Dafür muss Akteur B allerdings wissen mit welchen
|
||||
anderen Akteuren er in Verbindung steht und diese Verbindung aufrecht
|
||||
erhalten}
|
||||
}
|
||||
|
||||
\newglossaryentry{ui-lib}
|
||||
{
|
||||
name=UI-Bibliothek,
|
||||
plural=UI-Bibliotheken,
|
||||
description={
|
||||
kümmert sich um das Layout einer Webseite. Dabei unterscheidet man
|
||||
zwischen Design-Bibliotheken (wie Bootstrap), welche fertige
|
||||
UI-Komponenten bereitstellen, und Layout-Bibliotheken (wie Vue oder
|
||||
React.js), welche die Komponenten basierend auf Daten dynamisch
|
||||
anzeigen}
|
||||
}
|
||||
|
||||
\newglossaryentry{responsive}
|
||||
{
|
||||
name=Responsive,
|
||||
description={
|
||||
Design ist ein Design-Prinzip für Webseiten, bei dem die selbe Webseite ihre
|
||||
Komponenten dynamisch der Bildschirmbreite anpasst}
|
||||
}
|
||||
|
||||
\newglossaryentry{pseudoprotocol}
|
||||
{
|
||||
name=Pseudoprotokoll,
|
||||
description={
|
||||
ist ein URL-Schema, auf das Webseiten hören können, wenn sie sich das
|
||||
URL-Schema im Browser anmelden. Bekannt Pseudoprotokolle sind:
|
||||
,,mailto:'', ,,tel:'' oder ,,irc:''}
|
||||
}
|
||||
|
||||
\newglossaryentry{dashboard}
|
||||
{
|
||||
name=Dashboard,
|
||||
description={
|
||||
ist die erste Seite auf der man landet, wenn man angemeldet ist}
|
||||
}
|
||||
|
||||
\newglossaryentry{abo}
|
||||
{
|
||||
name=Abonnement,
|
||||
description={
|
||||
ist ein abonnierter Podcast}
|
||||
}
|
||||
|
||||
\newglossaryentry{discovery}
|
||||
{
|
||||
name=Discovery,
|
||||
description={
|
||||
ist ein Feature der Gpodder-API, welches dem Nutzer eine Reihe von
|
||||
Podcasts zum abonnieren anbietet}
|
||||
}
|
||||
|
||||
\newglossaryentry{session-token}
|
||||
{
|
||||
name=Session-Token,
|
||||
description={
|
||||
ist ein Wort, dass vom Client gespeichert wird solange der Nutzer
|
||||
eingeloggt ist und bei jeder Anfrage an den Server mitgeschickt wird.
|
||||
Der Server kann den Session-Token einem Nutzer zuordnen und so mit
|
||||
nutzerspezifischen Daten antworten}
|
||||
}
|
||||
|
||||
\newglossaryentry{cookie}
|
||||
{
|
||||
name=Cookie,
|
||||
description={
|
||||
ist ein kleiner webseitenspezifischer Speicher im Browser, welcher vom
|
||||
Server und von der Webseite gesetzt werden kann und bei jeder weiteren
|
||||
Anfrage an den Server mitgesendet wird. Cookies bleiben entweder
|
||||
temporär im Browserspeicher, bis der Browser geschlossen wird oder
|
||||
permanent, bis ein optionales Verfallsdatum erreicht ist}
|
||||
}
|
||||
|
||||
% UI-Framework (React.js/Vue/Bootstrap)
|
||||
% Responsive Design
|
||||
% Abonnement
|
||||
% Pseudoprotokoll
|
||||
% Dashboard
|
||||
|
83
00-pflichtenheft/sections/produktdaten.tex
Normal file
|
@ -0,0 +1,83 @@
|
|||
\section{Produktdaten}
|
||||
|
||||
Das Projekt erhebt an unterschiedlichen Stellen Daten des Benutzers oder anderen
|
||||
Plattformen. Diese Daten können temporär gespeichert werden. Dabei bleiben die
|
||||
Daten nur für eine kurze Zeit gespeichert, zum Beispiel so lange wie der Nutzer
|
||||
eingeloggt ist. Andere Daten können auch persistent gespeichert werden. Dabei
|
||||
bleiben die Daten solange gespeichert, bis sie manuell oder durch
|
||||
\Gls{garbage-collection} gelöscht werden.
|
||||
|
||||
\subsection{Weboberfläche}
|
||||
|
||||
Die Weboberfläche bezieht direkt Daten vom Benutzer. Die Weboberfläche erhält
|
||||
E-Mail-Adresse und Passwort vom Benutzer, speichert diese aber nur solange, bis
|
||||
diese an das Backend zur Validierung geschickt werden. Daraufhin erhält die
|
||||
Weboberfläche einen \Gls{session-token} welcher entweder persistent oder temporär als
|
||||
\Gls{cookie} gespeichert bleibt, je nachdem, ob der Nutzer angemeldet bleiben möchte.
|
||||
|
||||
Zusätzlich erhält die Weboberfläche die abonnierten \Glspl{podcast} und gehörten
|
||||
\Glspl{episode} inklusive Metadaten vom Backend. Diese Daten werden nur temporär,
|
||||
solange die Webseite offen ist, gespeichert.
|
||||
|
||||
\subsubsection*{Persistent}
|
||||
|
||||
\begin{itemize}
|
||||
\item \Gls{session-token} (falls der Nutzer angemeldet bleiben möchte)
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection*{Temporär}
|
||||
|
||||
\begin{itemize}
|
||||
\item Abonnierte \Glspl{podcast}
|
||||
\item Gehörte \Glspl{episode}
|
||||
\item \Gls{session-token}
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Backend}
|
||||
|
||||
Das Backend interagiert nicht direkt mit dem Benutzer, sondern bekommt Daten von
|
||||
der Weboberfläche und \Glspl{podcatcher}. Wenn sich ein Nutzer über die Weboberfläche
|
||||
oder im \Gls{podcatcher} anmeldet oder registriert speichert der Server temporär die E-Mail-Adresse und
|
||||
das Passwort des Nutzers im Klartext, bevor es die Daten gegen die gehashten und
|
||||
gesalzenen persistenten Daten der \Gls{db} abgleicht beziehungsweise speichert.
|
||||
|
||||
Außerdem speichert das Backend abonnierte \Glspl{podcast} und gehörte
|
||||
\Glspl{episode}, welche
|
||||
es vom \Gls{podcatcher} bekommt, im persistenten Speicher. Diese Daten bleiben
|
||||
gespeichert bis sie durch neue Daten obsolet werden (\Gls{garbage-collection}),
|
||||
vom Nutzer manuell gelöscht werden oder der Account gelöscht wird.
|
||||
|
||||
Wenn die Weboberfläche \Glspl{episode} über \Glspl{podcast} abfragt, welche noch nicht vom
|
||||
Nutzer gehört wurden, holt der Server Metadaten über den \Glspl{podcast} und speichert
|
||||
Informationen und Bilder des \Glspl{podcast} temporär, solange der Nutzer die
|
||||
Weboberfläche geöffnet hat.
|
||||
|
||||
\subsubsection*{Persistent}
|
||||
\begin{itemize}
|
||||
% Email (gehasht und gesalzen) / Betreuer fragen weil evtl Mails gesendet werden
|
||||
% müssen, falls Datenschutzbedinungen geändert werden
|
||||
\item E-Mail-Adresse gehasht und gesalzen
|
||||
\item Passwort gehasht und gesalzen
|
||||
\item Abonnierte \Glspl{podcast}
|
||||
\item Gehörte \Glspl{episode} (Hörfortschritte)
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection*{Temporär}
|
||||
\begin{itemize}
|
||||
\item Metadaten von Feeds (\Glspl{episode}, Bilder)
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Podcatcher}
|
||||
|
||||
Der \Gls{podcatcher} speichert die E-Mail-Adresse, das Passwort und die URL der
|
||||
Gpodder-Instanz im persistenten Speicher. Zusätzlich speichert der
|
||||
\Gls{podcatcher}
|
||||
abonnierte \Glspl{podcast} und gehörte \Glspl{episode} im persistenten Speicher.
|
||||
|
||||
\subsubsection*{Persistent}
|
||||
\begin{itemize}
|
||||
\item E-Mail-Adresse, Passwort und URL der Gpodder-Instanz
|
||||
\item Abonnierte \Glspl{podcast}
|
||||
\item Gehörte \Glspl{episode}
|
||||
\end{itemize}
|
||||
|
215
00-pflichtenheft/sections/produktfunktionen.tex
Normal file
|
@ -0,0 +1,215 @@
|
|||
\section{ Produktfunktionen }
|
||||
|
||||
\subsection{ Registrierung }
|
||||
\label{f:registrierung}
|
||||
|
||||
\begin{description}
|
||||
\item[Anwendungsfall:] Der Nutzer möchte sich registrieren.
|
||||
\item[Anforderungen:] \ref{r:login}
|
||||
\item[Test:] \ref{t:register}, \ref{t:pw-req}
|
||||
\item[Ziel:] Der Nutzer hat einen funktionierenden Account.
|
||||
\item[Vorbedingung:] -
|
||||
\item[Nachbedingung Erfolg:] Erfolgreiche Registrierung.
|
||||
\item[Nachbedingung Fehlschlag:] Registrierung/Verbindungsaufbau zum Server schlägt
|
||||
fehl.
|
||||
\item[Akteure:] Nutzer, Server
|
||||
\item[Auslösendes Ereignis:] Drücken des \enquote{Registrieren}-Buttons.
|
||||
\item[Beschreibung:] \mbox{}
|
||||
\begin{enumerate}
|
||||
\item Öffnen der Webseite.
|
||||
\item Drücken auf \enquote{Registrieren}-Option.
|
||||
\item E-Mail-Adresse und zwei Mal neues Passwort eingeben.
|
||||
\item \enquote{Registrieren}-Button drücken.
|
||||
\item Bestätigungs-E-Mail wird an angegebene E-Mail-Adresse gesendet.
|
||||
\item Nutzer öffnet Bestätigungs-Link.
|
||||
\item Nutzer wird auf Login-Seite weitergeleitet. Der Bestätigungs-Link verfällt.
|
||||
\end{enumerate}
|
||||
\item[Erweiterung:] Wenn der Link nach 24 Stunden noch nicht angeklickt wurde, verfällt \\
|
||||
dieser.
|
||||
\end{description}
|
||||
|
||||
\newpage
|
||||
|
||||
\subsection{ Anmelden }
|
||||
\label{f:anmelden}
|
||||
|
||||
\begin{description}
|
||||
\item[Anwendungsfall:] Der Nutzer möchte sich anmelden
|
||||
\item[Anforderungen:] \ref{r:login}, \ref{r:login-provider}
|
||||
\item[Test:] \ref{t:login}
|
||||
\item[Ziel:] Der Nutzer ist eingeloggt.
|
||||
\item[Vorbedingung:] Der Nutzer hat einen funktionierenden Account.
|
||||
\item[Nachbedingung Erfolg:] Erfolgreiche Anmeldung
|
||||
\item[Nachbedingung Fehlschlag:] Anmeldung/Verbindungsaufbau zum Server schlägt
|
||||
fehl.
|
||||
\item[Akteure:] Nutzer, Server
|
||||
\item[Auslösendes Ereignis:] Drücken des \enquote{Anmelden}-Buttons.
|
||||
\item[Beschreibung:] \mbox{}
|
||||
\begin{enumerate}
|
||||
\item Öffnen der Webseite.
|
||||
\item E-Mail-Adresse und Passwort eingeben.
|
||||
\item Option \enquote{Passwort merken} aus-/abwählen.
|
||||
\item \enquote{Anmelden}-Button drücken.
|
||||
\item Nutzer wird zu seinem \Gls{dashboard} weitergeleitet.
|
||||
\end{enumerate}
|
||||
\item[Erweiterung:] Wenn die Option \enquote{Passwort merken} aktiviert ist, bleibt der Nutzer \\
|
||||
sitzungsübergreifend in seinem Account eingeloggt.
|
||||
\item[Alternativen:] \mbox{}
|
||||
\begin{enumerate}
|
||||
\item Falls sich der Browser einen vorherigen Login gemerkt hat,
|
||||
wird der Nutzer beim Aufruf der Seite direkt zu seinem
|
||||
\Gls{dashboard} weitergeleitet.
|
||||
\item Der Nutzer meldet sich mit einem \Gls{oauth} Dienst an.
|
||||
\end{enumerate}
|
||||
\end{description}
|
||||
|
||||
\newpage
|
||||
|
||||
\subsection{ Passwort vergessen }
|
||||
\label{f:pwreset}
|
||||
|
||||
\begin{description}
|
||||
\item[Anwendungsfall:] Der Nutzer hat sein Passwort vergessen und möchte es zurücksetzen.
|
||||
\item[Anforderungen:] \ref{r:reset-pw}
|
||||
\item[Test:] \ref{t:pw-req}, \ref{t:forgot-pw}
|
||||
\item[Ziel:] Der Nutzer hat ein neues Passwort.
|
||||
\item[Vorbedingung:] Der Nutzer hat einen bestehenden Account und Zugriff auf seine E-Mail-Adresse
|
||||
\item[Nachbedingung Erfolg:] Erfolgreiche Passwort Zurücksetzung.
|
||||
\item[Nachbedingung Fehlschlag:] Zurücksetzung des Passworts / Verbindungsaufbau zum Server
|
||||
schlägt fehl.
|
||||
\item[Akteure:] Nutzer, Server
|
||||
\item[Auslösendes Ereignis:] Drücken der \enquote{Passwort-Vergessen} Option auf der Login-Seite.
|
||||
\item[Beschreibung:] \mbox{}
|
||||
\begin{enumerate}
|
||||
\item Öffnen der Webseite.
|
||||
\item \enquote{Passwort-Vergessen} Option auswählen.
|
||||
\item Weiterleitung auf \enquote{Passwort zurücksetzen} Seite.
|
||||
\item E-Mail-Adresse des Accounts eingeben. Falls kein Account mit dieser
|
||||
Adresse existiert, wird dieser Schritt wiederholt.
|
||||
\item Bestätigungs-E-Mail mit Zurücksetzungs-Link wird an die angegebene
|
||||
E-Mail-Adresse gesendet.
|
||||
\item Der Nutzer öffnet den Zurücksetzungs-Link.
|
||||
\item Ein Neues Passwort zweimal eingeben.
|
||||
\item Auf den \enquote{Passwort-Zurücksetzen}-Button klicken.
|
||||
\item Weiterleitung auf Login-Seite.
|
||||
\end{enumerate}
|
||||
\end{description}
|
||||
|
||||
\newpage
|
||||
|
||||
\subsection{ Passwort ändern }
|
||||
\label{f:pwchange}
|
||||
|
||||
\begin{description}
|
||||
\item[Anwendungsfall:] Der Nutzer möchte sein Passwort ändern.
|
||||
\item[Anforderungen:] \ref{r:reset-pw}
|
||||
\item[Test:] \ref{t:pw-req}, \ref{t:change-pw}
|
||||
\item[Ziel:] Der Nutzer hat ein neues Passwort.
|
||||
\item[Vorbedingung:] Der Nutzer ist in seinem Account angemeldet.
|
||||
\item[Nachbedingung Erfolg:] Erfolgreiche Passwort Änderung.
|
||||
\item[Nachbedingung Fehlschlag:] Änderung des Passworts / Verbindungsaufbau zum Server
|
||||
schlägt fehl.
|
||||
\item[Akteure:] Nutzer, Server
|
||||
\item[Auslösendes Ereignis:] Betätigen des \enquote{Passwort-Ändern}-Buttons.
|
||||
\item[Beschreibung:] \mbox{}
|
||||
\begin{enumerate}
|
||||
\item Öffnen der Webseite.
|
||||
\item Anmelden
|
||||
\item Auf Account-Einstellungen gehen.
|
||||
\item Bisheriges Passwort und zweimal neues Passwort in dafür vorgesehene Felder
|
||||
eintippen.
|
||||
\item \enquote{Passwort-Ändern}-Button betätigen.
|
||||
\end{enumerate}
|
||||
\end{description}
|
||||
|
||||
\newpage
|
||||
|
||||
\subsection{ Hörfortschritt synchronisieren }
|
||||
\label{f:hörfortschrittSync}
|
||||
|
||||
\begin{description}
|
||||
\item[Anwendungsfall:] Der Nutzer hört mit einem verknüpften
|
||||
\Gls{podcatcher} eine \Gls{episode} bis zu
|
||||
einem gewissen Zeitpunkt.
|
||||
Der Hörfortschritt soll mit dem Server und allen anderen Geräten synchronisiert werden.
|
||||
\item[Anforderungen:] \ref{r:sync}, \ref{r:store}, \ref{r:persistent-storage}, \ref{r:gpodder}
|
||||
\item[Test:] \ref{t:sync-episode}
|
||||
\item[Ziel:] Der Hörfortschritt wird auf den Server und alle verknüpften Geräte übertragen.
|
||||
\item[Vorbedingung:] Der Nutzer hat seinen Account mit einem \Gls{podcatcher} verknüpft und verwendet
|
||||
diesen im Folgenden.
|
||||
\item[Nachbedingung Erfolg:] Erfolgreiche Synchronisation des Hörfortschritts.
|
||||
\item[Nachbedingung Fehlschlag:] Verbindungsaufbau zum Server schlägt
|
||||
fehl.
|
||||
\item[Akteure:] Nutzer, \Gls{podcatcher}, Server
|
||||
\item[Auslösendes Ereignis:] Anhören einer \Gls{episode} bis zu einem gewissen Zeitpunkt.
|
||||
\item[Beschreibung:] \mbox{}
|
||||
\begin{enumerate}
|
||||
\item Der Nutzer hört innerhalb eines \Gls{podcatcher}s eine
|
||||
\Gls{episode}.
|
||||
\item Der Hörfortschritt wird dem Server über die \Gls{gpodder} mitgeteilt.
|
||||
\item Der Server aktualisiert den Hörfortschritt im entsprechenden Datensatz
|
||||
des Nutzeraccounts zur \Gls{episode}.
|
||||
\end{enumerate}
|
||||
\item[Erweiterung:] Wenn sich ein weiterer \Gls{podcatcher} aktualisiert, ruft dieser
|
||||
die neuen Hörfortschritte des Nutzers vom Server über die \Gls{gpodder} ab und wendet diese an.
|
||||
\end{description}
|
||||
|
||||
\newpage
|
||||
|
||||
\subsection{ Abonnements synchronisieren}
|
||||
\label{f:abonnentsSync}
|
||||
|
||||
\begin{description}
|
||||
\item[Anwendungsfall:] Der Nutzer fügt auf einem verknüpften
|
||||
\Gls{podcatcher} ein \Gls{abo} hinzu bzw. löscht ein \Gls{abo}.
|
||||
Dieses soll mit dem Server und allen anderen Geräten synchronisiert werden.
|
||||
\item[Anforderungen:] \ref{r:sync}, \ref{r:store}, \ref{r:persistent-storage}, \ref{r:gpodder}
|
||||
\item[Test:] \ref{t:sync-sub}, \ref{t:sync-unsub}
|
||||
\item[Ziel:] Das (De-)\Gls{abo} wird auf den Server und alle verknüpften Geräte übertragen.
|
||||
\item[Vorbedingung:] Der Nutzer hat seinen Account mit einem \Gls{podcatcher} verknüpft und verwendet
|
||||
diesen im Folgenden.
|
||||
\item[Nachbedingung Erfolg:] Erfolgreiche Synchronisation des \Glspl{abo}.
|
||||
\item[Nachbedingung Fehlschlag:] Verbindungsaufbau zum Server schlägt
|
||||
fehl.
|
||||
\item[Akteure:] Nutzer, \Gls{podcatcher}, Server
|
||||
\item[Auslösendes Ereignis:] (De-)Abonnieren eines \Glspl{podcast} innerhalb
|
||||
eines \Gls{podcatcher}.
|
||||
\item[Beschreibung:] \mbox{}
|
||||
\begin{enumerate}
|
||||
\item Der Nutzer (de-)abonniert innerhalb eines \Gls{podcatcher}s einen
|
||||
\Gls{podcast}.
|
||||
\item Die Änderung wird dem Server über die \Gls{gpodder} mitgeteilt.
|
||||
\item Der Server fügt das neue \Gls{abo} persistent zum Datensatz des Nutzers
|
||||
auf dem Server hinzu / löscht das \Gls{abo} vom Datensatz auf
|
||||
dem Server.
|
||||
\end{enumerate}
|
||||
\item[Erweiterung:] Wenn sich ein weiterer \Gls{podcatcher} aktualisiert, holt dieser
|
||||
die aktuelle Liste der \Glspl{abo} des Nutzers vom Server über die
|
||||
\Gls{gpodder} (Client Pull).
|
||||
\end{description}
|
||||
|
||||
\newpage
|
||||
|
||||
\subsection{ Account löschen}
|
||||
\label{f:deleteAccount}
|
||||
|
||||
\begin{description}
|
||||
\item[Anwendungsfall:] Der Nutzer möchte seinen Account löschen.
|
||||
\item[Anforderungen:] \ref{r:delete-acc}
|
||||
\item[Test:] \ref{t:delete-acc}
|
||||
\item[Ziel:] Der Account und alle Nutzerdaten werden vom Server gelöscht.
|
||||
\item[Vorbedingung:] Der Nutzer ist angemeldet und befindet sich auf der Einstellungsseite.
|
||||
\item[Nachbedingung Erfolg:] Der Account wurde gelöscht.
|
||||
\item[Nachbedingung Fehlschlag:] Verbindungsaufbau zum Server schlägt
|
||||
fehl.
|
||||
\item[Akteure:] Nutzer, Server
|
||||
\item[Auslösendes Ereignis:] Der Nutzer drückt auf den \enquote{Account löschen} Knopf.
|
||||
\item[Beschreibung:] \mbox{}
|
||||
\begin{enumerate}
|
||||
\item Der Nutzer drückt auf den \enquote{Account löschen}-Knopf.
|
||||
\item Der Nutzer wird dazu aufgefordert sein Passwort als Bestätigung der Löschung
|
||||
einzugeben.
|
||||
\item Der Server löscht den Account und alle dazugehörigen Daten.
|
||||
\item Der Nutzer wird auf die Login-Seite weitergeleitet.
|
||||
\end{enumerate}
|
||||
\end{description}
|
184
00-pflichtenheft/sections/produktuebersicht.tex
Normal file
|
@ -0,0 +1,184 @@
|
|||
\section{Produktübersicht}
|
||||
|
||||
In diesem Kapitel wird der Aufbau der Synchronisationsserver-Webseite in einem Use-Case-Diagramm, welches sich in Abbildung
|
||||
\ref{fig:UseCase} befindet, visualisiert.
|
||||
|
||||
Hierbei wird in Aktivitätsdiagrammen näher auf die Aktionen \enquote{Anmelden} (Abbildung \ref{fig:ActLogin}),
|
||||
\enquote{Registrieren} (Abbildung \ref{fig:ActRegister}) und \enquote{Passwort vergessen} (Abbildung \ref{fig:ActResetPass})
|
||||
eingegangen.
|
||||
|
||||
Weiter beschreibt ein abstrahiertes Sequenzdiagramm (Abbildung
|
||||
\ref{fig:SeqSynchSubs}) den Nachrichtenaustausch bei der Synchronisation der
|
||||
gespeicherten Daten eines Benutzers. Dies erfolgt am Beispiel der Tätigung eines
|
||||
neuen \Glspl{abo} über einen \Gls{podcatcher}.
|
||||
|
||||
\subsection{Der Aufbau der Webseite}
|
||||
|
||||
In dem Use-Case-Diagramm in Abbildung \ref{fig:UseCase} erkennt man den Aufbau der Webseite des Synchronisationsservers.
|
||||
Besucht man die Seite ohne eingeloggt zu sein, so hat man die Möglichkeit die Sprache zu ändern, sich anzumelden, sich zu registrieren oder sein Passwort über die \enquote{Passwort vergessen}-Funktion \ref{f:pwreset} zurückzusetzen.
|
||||
Dabei gibt es die Möglichkeit sich mit seinem Google-Konto oder dem Konto eines anderen Anbieters zu registrieren / anzumelden.
|
||||
|
||||
Ist man angemeldet, wird man auf ein \Gls{dashboard} weitergeleitet.
|
||||
Dort hat man die Möglichkeit eine Anleitung einzusehen und die bisher
|
||||
abonnierten \Glspl{podcast} einzusehen.
|
||||
Dabei erhält man zu jedem \Gls{podcast} einen Überblick über dessen
|
||||
\Glspl{episode} und Details darüber, bis zu welchem Zeitpunkt man die
|
||||
\Gls{episode} angehört hat.
|
||||
Auch gibt es die Möglichkeit einen Verlauf und den korrespondierenden
|
||||
Fortschritt aller zuletzt gehörten \Glspl{episode} einzusehen.
|
||||
|
||||
Des Weiteren kann man das eigene Profil verwalten.
|
||||
Dies beinhaltet das Ändern des eigenen Passworts, das Importieren der Daten einer Gpodder-Instanz über eine Anmeldung oder
|
||||
dem Importieren als Datei.
|
||||
Auch können in der Profilverwaltung personenbezogene Daten als Datei importiert und exportiert werden.
|
||||
Schließlich hat man in der Profilverwaltung die Möglichkeit den eigenen Account permanent zu löschen.
|
||||
|
||||
Ist man ein Administrator, so hat man zusätzlich die Möglichkeit Statistiken einzusehen.
|
||||
|
||||
\newpage
|
||||
|
||||
% UML Use-Case Diagramm
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\hspace*{-2.5cm}
|
||||
\input{sections/TikzPictures/UseCaseUML}
|
||||
\caption{Use-Case-Diagramm der Webseite\\(*) - Optionale Funktionen, deren Implementierung nicht feststeht}
|
||||
\label{fig:UseCase}
|
||||
\end{figure}
|
||||
\newpage
|
||||
|
||||
\subsection{Das Einloggen}
|
||||
|
||||
Im Aktivitätsdiagramm \enquote{Anmeldung} in Abbildung \ref{fig:ActLogin} möchte der Nutzer sich auf der Webseite anmelden.
|
||||
Hierzu ruft der Nutzer zunächst die Webseite auf und landet auf der Login Seite.
|
||||
|
||||
Hat der Nutzer sich bereits zuvor auf dem Computer auf der Seite angemeldet und dabei ausgewählt eingeloggt zu bleiben,
|
||||
so wird der Nutzer über Session-\Glspl{cookie} automatisch auf das \Gls{dashboard} weitergeleitet.
|
||||
Ist das nicht der Fall, so muss der Nutzer seine Anmeldedaten eingeben.
|
||||
|
||||
Nach dem Eintragen der Daten hat der Nutzer die Möglichkeit für das nächste Mal, wenn der Nutzer die Webseite
|
||||
am selben Computer betritt, angemeldet zu bleiben.
|
||||
Daraufhin drückt der Nutzer den \enquote{Anmelden}-Button.
|
||||
|
||||
Wurde die E-Mail oder das Passwort falsch eingegeben, so zeigt die Seite eine Fehlermeldung an und der Nutzer wird aufgefordert seine Eingabe zu korrigieren.
|
||||
Wurden die E-Mail und das Passwort korrekt eingegeben, so landet der Nutzer
|
||||
angemeldet auf dem \Gls{dashboard}, von wo aus er dann alle Aktionen ausführen kann, für die man angemeldet sein muss.
|
||||
|
||||
\newpage
|
||||
|
||||
% UML Activity Diagramm - Login
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\input{sections/TikzPictures/ActivityLogin}
|
||||
\caption{Aktivitätsdiagramm - Anmelden}
|
||||
\label{fig:ActLogin}
|
||||
\end{figure}
|
||||
\newpage
|
||||
|
||||
\subsection{Das Registrieren}
|
||||
|
||||
Möchte sich der Nutzer einen neuen Account erstellen, so läuft dieser Vorgang
|
||||
entsprechend dem Aktivitätsdiagramm \enquote{Registrieren} in Abbildung \ref{fig:ActRegister} ab.
|
||||
Der Nutzer ruft zunächst die Webseite auf und landet auf der Login Seite.
|
||||
Dort wählt der Nutzer die \enquote{Registrieren}-Option aus und wird zur Registrierungsseite weitergeleitet.
|
||||
|
||||
Auf der Registrierungsseite gibt der Nutzer in den jeweils dafür zugeordneten Eingabefeldern seine E-Mail-Adresse und zur Kontrolle
|
||||
zwei Mal das gleiche Passwort ein, welches dem Account zugeordnet werden soll.
|
||||
Daraufhin drückt der Nutzer zum Abschluss den \enquote{Registrieren}-Button.
|
||||
Der Server überprüft, ob die E-Mail-Adresse bereits vergeben ist und ob das Passwort die Passwortmindestanforderungen \ref{r:pw-requirements} erfüllt.
|
||||
|
||||
Ist die E-Mail schon vergeben, so wird dem Nutzer eine entsprechende Meldung angezeigt und der Nutzer muss die eingegebene E-Mail-Adresse korrigieren.
|
||||
Erfüllt das Passwort nicht die Mindestvoraussetzungen, so wird dem Nutzer auch hier eine entsprechende Meldung angezeigt und der Nutzer muss die Eingabe korrigieren.
|
||||
|
||||
Erfüllen die Eingaben die Voraussetzungen, so wird an die angegebene E-Mail-Adresse eine E-Mail mit einem Link zur Verifizierung
|
||||
der E-Mail-Adresse geschickt.
|
||||
Der Nutzer muss diesen Link innerhalb der nächsten 24 Stunden zur Aktivierung seines Kontos öffnen, da ansonsten der Link
|
||||
abläuft und der Nutzer den Prozess erneut beginnen muss.
|
||||
|
||||
Wurde der Link innerhalb von 24 Stunden geöffnet, so wird der Account aktiviert und der Nutzer wird über den Link zur Login Seite
|
||||
weitergeleitet, von wo aus er sich mit seinem neu erstellten Account nun einloggen kann.
|
||||
|
||||
\newpage
|
||||
|
||||
% UML Activity Diagram - Register
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\input{sections/TikzPictures/ActivityRegister}
|
||||
\caption{Aktivitätsdiagramm - Registrieren}
|
||||
\label{fig:ActRegister}
|
||||
\end{figure}
|
||||
\newpage
|
||||
|
||||
\subsection{Das Vergessen des Passwortes}
|
||||
|
||||
Hat der Nutzer einmal sein Passwort vergessen, so gibt es die Möglichkeit das Passwort zurückzusetzen.
|
||||
Wie dieser Vorgang aussieht, wird im Aktivitätsdiagramm \enquote{Passwort zurücksetzen} in Abbildung \ref{fig:ActResetPass}
|
||||
dargestellt.
|
||||
Zunächst ruft der Nutzer die Webseite auf und landet auf der Login Seite.
|
||||
Über die Option \enquote{Passwort vergessen} wird der Nutzer auf die \enquote{Passwort vergessen}-Seite weitergeleitet.
|
||||
|
||||
Hier gibt der Nutzer in einem Eingabefeld die E-Mail-Adresse des Accounts an, dessen Passwort der Nutzer vergessen hat.
|
||||
Nach der Bestätigung der Eingabe überprüft der Server, ob unter der angegebenen E-Mail-Adresse ein Account angelegt ist.
|
||||
Ist dies nicht der Fall, so wird der Nutzer erneut darum gebeten die E-Mail-Adresse anzugeben.
|
||||
Existiert ein Account unter der angegeben E-Mail-Adresse, so wird eine E-Mail an die angegebene Adresse geschickt, die einen
|
||||
automatisch generierten Link enthält, der es dem Nutzer erlaubt das Passwort für den jeweiligen Account zurückzusetzen.
|
||||
|
||||
Der Nutzer muss den Link innerhalb der nächsten 24 Stunden öffnen, da dieser ansonsten abläuft und zu einer entsprechenden
|
||||
Fehlermeldung führt.
|
||||
Öffnet der Nutzer den Link innerhalb von 24 Stunden, so wird der Nutzer auf eine Seite weitergeleitet auf der der Nutzer
|
||||
zwei Mal das neue Passwort eingeben muss.
|
||||
Das Passwort muss dabei die Passwortmindestanforderungen \ref{r:pw-requirements} erfüllen.
|
||||
|
||||
Ist das neue Passwort eingegeben, so muss der Nutzer den \enquote{Passwort zurücksetzen}-Button drücken und das eingegebene Passwort wird überprüft.
|
||||
Erfüllt das Passwort die Mindestanforderungen nicht, so wird dem Nutzer eine entsprechende Fehlermeldung angezeigt und der Nutzer muss sich ein neues Passwort ausdenken und zwei Mal eingeben.
|
||||
Erfüllt das Passwort die Mindestanforderungen, so wird das neue Passwort für den Account gespeichert und der Nutzer wird auf die Login Seite weitergeleitet, von wo aus er sich mit dem neuen Passwort anmelden kann.
|
||||
|
||||
\newpage
|
||||
|
||||
% UML Activity Diagram - Reset Password
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\input{sections/TikzPictures/ActivityResetPass}
|
||||
\caption{Aktivitätsdiagramm - Passwort vergessen}
|
||||
\label{fig:ActResetPass}
|
||||
\end{figure}
|
||||
\newpage
|
||||
|
||||
\subsection{Das Synchronisieren am Beispiel eines Abonnements}
|
||||
|
||||
Der Benutzer in Abbildung \ref{fig:SeqSynchSubs} hört \Glspl{podcast} über die
|
||||
verschiedenen \Gls{podcatcher}-Applika\-tionen \enquote{Podcatcher1} und \enquote{Podcatcher2}.
|
||||
Dabei spielt es im Folgenden keine Rolle ob er beide Applikationen auf demselben Gerät, beide auf jeweils unterschiedlichen Geräten oder die gleiche Applikation auf unterschiedlichen Geräten verwendet.
|
||||
|
||||
Der Benutzer tätigt ein neues \Gls{abo} über die \Gls{podcatcher}-Applikation \enquote{Podcatcher1}.
|
||||
Dies bewirkt zunächst eine lokale Änderung der Liste der \Glspl{abo}.
|
||||
Im Zuge dessen wird auch der Server über die vorgenommene Änderung benachrichtigt.
|
||||
Dieser speichert dann die kommunizierte Änderung persistent in der \Gls{db}.
|
||||
|
||||
Im Folgenden lässt sich der Benutzer die Liste seiner \Glspl{abo} im Webfrontend anzeigen.
|
||||
Dafür benachrichtigt das Webfrontend den Server darüber, dass es die Liste der
|
||||
\Glspl{abo} des entsprechenden Nutzers benötigt (\enquote{Client Pull}).
|
||||
Das Webfrontend erhält die aktuelle Liste, welche insbesondere das zuvor
|
||||
getätigte \Gls{abo} enthält, und zeigt diese dem Nutzer an.
|
||||
|
||||
Der Benutzer lässt sich nun auch in der \Gls{podcatcher}-Applikation
|
||||
\enquote{Podcatcher2} die Liste seiner \Glspl{abo} anzeigen.
|
||||
Die Anwendung \enquote{Podcatcher2} benachrichtigt hierfür nach kurzer Zeit oder
|
||||
nach manueller Anforderung den Server darüber, dass sie die Liste der
|
||||
\Glspl{abo} des entsprechenden Nutzers benötigt.
|
||||
|
||||
Die Anwendung erhält die aktuelle Liste, übernimmt diese lokal und zeigt sie dem Nutzer an.
|
||||
So wird der aktuelle Stand der Liste der \Glspl{abo} (analog der Fortschritt
|
||||
beim Anhören/Ansehen von \Glspl{episode}) über alle verbundenen \Gls{podcatcher} (und entsprechend alle verbundenen Geräte) synchronisiert.
|
||||
|
||||
\newpage
|
||||
|
||||
% UML Sequence Diagram - Synchronise Subscription
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\raisebox{3cm}{
|
||||
\input{sections/TikzPictures/SequenceSynchroniseSubscription}}
|
||||
\caption{Sequenzdiagramm - Synchronisation am Beispiel Abonnieren}
|
||||
\label{fig:SeqSynchSubs}
|
||||
\end{figure}
|
||||
\newpage
|
605
00-pflichtenheft/sections/tests.tex
Normal file
|
@ -0,0 +1,605 @@
|
|||
|
||||
\section{Tests}
|
||||
|
||||
\subsection{Registrierung}\label{t:register}
|
||||
\vspace{0.3cm}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Ein Fenster ist im Browser geöffnet.
|
||||
\item [Aktion] Der Benutzer gibt die URL der Weboberfläche in die Kopfzeile ein und drückt Enter.
|
||||
\item [Reaktion] Der Browser wechselt zur Anmeldeseite der Weboberfläche.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Anmeldeseite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer klickt auf den Knopf \enquote{Registrieren}.
|
||||
\item [Reaktion] Der Browser wechselt zur Registrierungsseite.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Registrierungsseite mit Registrierungsmöglichkeit in der Mitte des Fensters ist geladen.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{pseIstToll@test.com} als E-Mail und \enquote{Test123!?} als Passwort ein. Weiter gibt er \enquote{test123!?} in das \enquote{Wiederholen} Feld ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
|
||||
\item [Reaktion] Die Registrierungsseite bleibt geladen. Im E-Mail-Feld steht \enquote{pseIstToll@test.com}, im Feld \enquote{Passwort} steht \enquote{Test123!?} und im Feld \enquote{Wiederholen} steht \enquote{test123!?}. Der Benutzer wird aufgefordert in die Felder \enquote{Passwort} und \enquote{Wiederholen} das gleiche Passwort einzugeben.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Registrierungsseite ist geladen. Als E-Mail ist \enquote{pseIstToll@test\-.com}, als Passwort \enquote{Test123!?} und \enquote{test123!?} in das Feld \enquote{Wiederholen} eingetragen.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{Test123!?} in das Feld \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
|
||||
\item [Reaktion] Dem Benutzer wird angezeigt, dass an die angegebene E-Mail-Adres\-se eine E-Mail mit einem Bestätigungslink versendet wurde. Der Benutzer wird aufgefordert diesen zu Bestätigen um die Registrierung abzuschließen.
|
||||
\end{description}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer hat die Registrierung begonnen und die E-Mail mit dem Bestä\-tigungs-Link erhalten. Der Benutzer hat noch nicht auf den Bestätigungs-Link geklickt.
|
||||
\item [Aktion] Der Benutzer klickt innerhalb von 24 Stunden nach Versendung auf den Bestätigungs-Link.
|
||||
\item [Reaktion] Der Account wird erstellt und der Benutzer wird auf die Anmeldeseite weitergeleitet.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer hat die Registrierung bereits abgeschlossen.
|
||||
\item [Aktion] Der Benutzer klickt auf den Bestätigungs-Link.
|
||||
\item [Reaktion] Der Benutzer erhält eine Fehlermeldung, dass der Link abgelaufen ist.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer hat die Registrierung begonnen und die E-Mail mit dem Bestä\-tigungs-Link erhalten. Die E-Mail wurde vor mehr als 24 Stunden versendet. Der Benutzer hat den Bestätigungs-Link noch nicht angeklickt.
|
||||
\item [Aktion] Der Benutzer klickt auf den Bestätigungs-Link.
|
||||
\item [Reaktion] Der Benutzer erhält eine Fehlermeldung, dass der Link abgelaufen ist. Der Account wird nicht erstellt. Der Benutzer wird auf die Anmeldeseite weitergeleitet.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Registrierungsseite ist geladen. Es ist bereits ein Account mit der E-Mail-Adresse \enquote{pseIstToll@test.com} registriert.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{pseIstToll@test.com} als E-Mail-Adresse und \enquote{Test123!?} als Passwort ein. Weiter gibt er das gleiche Passwort in das Feld \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
|
||||
\item [Reaktion] Die Registrierungsseite bleibt geladen. Es wird eine Fehlermeldung ausgegeben, dass diese E-Mail-Adresse bereits vergeben ist.\\
|
||||
\end{description}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
|
||||
|
||||
\subsection{Passwort Anforderungen}\label{t:pw-req}
|
||||
\vspace{0.3cm}
|
||||
|
||||
\begin{description}
|
||||
\item [Anmerkung] Die Testfälle sind beispielhaft für den Vorgang der Registrierung entworfen worden. Es wird analoges Verhalten bei den Vorgängen \enquote{Passwort ändern} \ref{t:change-pw} und \enquote{Passwort vergessen} \ref{t:forgot-pw} erwartet.
|
||||
\end{description}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Registrierungsseite ist geladen. Als E-Mail-Adresse ist \enquote{pseIstToll@test\-.com} eingetragen.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{test} in die Felder \enquote{Passwort} und \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
|
||||
\item [Reaktion] Die Registrierungsseite bleibt geladen. Dem Benutzer wird angezeigt das sein Passwort nicht die Passwort-Mindestanforderungen erfüllt. Weiter wird farblich angezeigt, dass sein Passwort nicht:
|
||||
\color{red}
|
||||
\begin{itemize}
|
||||
\item mindestens 8 Zeichen lang ist.
|
||||
\item mindestens einen Großbuchstaben enthält.
|
||||
\item mindestens eine Zahl enthält.
|
||||
\item mindestens ein Sonderzeichen enthält.
|
||||
\end{itemize}
|
||||
\color{black}
|
||||
Dem Benutzer wird farblich angezeigt dass sein Passwort:
|
||||
\color{ForestGreen}
|
||||
\begin{itemize}
|
||||
\item mindestens einen Kleinbuchstaben enthält.
|
||||
\end{itemize}
|
||||
\color{black}
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Registrierungsseite ist geladen. Als E-Mail ist \enquote{pseIstToll@test.com} eingetragen.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{Test123} in die Felder \enquote{Passwort} und \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
|
||||
\item [Reaktion] Die Registrierungsseite bleibt geladen. Dem Benutzer wird angezeigt das sein Passwort nicht die Passwort-Mindestanforderungen erfüllt. Weiter wird farblich angezeigt, dass sein Passwort nicht:
|
||||
\color{red}
|
||||
\begin{itemize}
|
||||
\item mindestens 8 Zeichen lang ist.
|
||||
\item mindestens ein Sonderzeichen enthält.
|
||||
\end{itemize}
|
||||
\color{black}
|
||||
Dem Benutzer wird farblich angezeigt dass sein Passwort:
|
||||
\color{ForestGreen}
|
||||
\begin{itemize}
|
||||
\item mindestens einen Kleinbuchstaben enthält.
|
||||
\item mindestens einen Großbuchstaben enthält.
|
||||
\item mindestens eine Zahl enthält.
|
||||
\end{itemize}
|
||||
\color{black}
|
||||
\end{description}
|
||||
|
||||
\newpage
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Registrierungsseite ist geladen. Als E-Mail-Adresse ist \enquote{pseIstToll@test\-.com} eingetragen.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{TEST123?} in die Felder \enquote{Passwort} und \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
|
||||
\item [Reaktion] Die Registrierungsseite bleibt geladen. Dem Benutzer wird angezeigt das sein Passwort nicht die Passwort-Mindestanforderungen erfüllt. Weiter wird farblich angezeigt, dass sein Passwort nicht:
|
||||
\color{red}
|
||||
\begin{itemize}
|
||||
\item mindestens einen Kleinbuchstaben enthält.
|
||||
\end{itemize}
|
||||
\color{black}
|
||||
Dem Benutzer wird farblich angezeigt dass sein Passwort:
|
||||
\color{ForestGreen}
|
||||
\begin{itemize}
|
||||
\item mindestens 8 Zeichen lang ist.
|
||||
\item mindestens einen Großbuchstaben enthält.
|
||||
\item mindestens eine Zahl enthält.
|
||||
\item mindestens ein Sonderzeichen enthält.
|
||||
\end{itemize}
|
||||
\color{black}
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Registrierungsseite ist geladen. Als E-Mail ist \enquote{pseIstToll@test.com} eingetragen.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{Test123!?} in die Felder \enquote{Passwort} und \enquote{Wiederholen} ein. Dann klickt der Benutzer auf den Knopf \enquote{Registrieren}.
|
||||
\item [Reaktion] Dem Benutzer wird angezeigt, dass an die angegebene E-Mail-Adresse eine E-Mail mit einem Bestätigungslink versendet wurde. Der Benutzer wird aufgefordert diesen zu bestätigen um die Registrierung abzuschließen.\\
|
||||
\end{description}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
|
||||
|
||||
\subsection{Anmeldung}\label{t:login}
|
||||
\vspace{0.3cm}
|
||||
|
||||
\begin{description}
|
||||
\item [Vorbedingung] Es ist nur ein Benutzer registriert. Dieser hat die E-Mail \enquote{pseIstToll@test\-.com} und das Passwort \enquote{Test123!?}. Die Option \enquote{Angemeldet bleiben} wurde nicht verwendet.
|
||||
\end{description}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Ein Fenster ist im Browser geöffnet.
|
||||
\item [Aktion] Der Benutzer gibt die URL der Weboberfläche in die Kopfzeile ein und drückt Enter.
|
||||
\item [Reaktion] Der Browser wechselt zur Anmeldeseite der Weboberfläche.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Anmeldeseite mit Anmeldemöglichkeit in der Mitte des Fensters ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer macht keine Eingaben und klickt auf den Knopf \enquote{Anmelden}.
|
||||
\item [Reaktion] Die Anmeldeseite bleibt geladen. Der Benutzer wird aufgefordert die Felder \enquote{E-Mail-Adresse} und \enquote{Passwort} auszufüllen.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Anmeldeseite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt als E-Mail-Adresse \enquote{pseIstToll@test.com} ein aber gibt kein Passwort ein. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
|
||||
\item [Reaktion] Die Anmeldeseite bleibt geladen. Im E-Mail-Feld ist \enquote{pseIstToll@test\-.com} eingetragen. Der Benutzer wird aufgefordert das Passwort-Feld auszufüllen.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Anmeldeseite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstSuperToll@test.com} ein und gibt \enquote{Test123!?} als Passwort ein. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
|
||||
\item [Reaktion] Die Anmeldeseite bleibt geladen. Als E-Mail ist \enquote{pseIstSuperToll@test\-.com} und als Passwort \enquote{Test123!?} eingetragen. Dem Benutzer wird eine Fehlermeldung ausgegeben: \enquote{E-Mail-Adresse oder Passwort ist ungültig!}
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Anmeldeseite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstToll@test.com} ein und gibt \enquote{test} als Passwort ein. Der Benutzer wählt die Option \enquote{Angemeldet bleiben} aus. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
|
||||
\item [Reaktion] Die Anmeldeseite bleibt geladen. Als E-Mail ist \enquote{pseIstToll@test.com} und als Passwort \enquote{test} eingetragen. Die Option \enquote{Angemeldet bleiben} ist ausgewählt. Dem Benutzer wird eine Fehlermeldung ausgegeben: \enquote{E-Mail-Adresse oder Passwort ist ungültig!}
|
||||
\end{description}
|
||||
|
||||
\newpage
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Anmeldeseite ist im Browser geladen. Als E-Mail ist \enquote{pseIstToll@test\-.com} und als Passwort \enquote{test} eingetragen. Die Option \enquote{Angemeldet bleiben} ist ausgewählt.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{Test123!?} als Passwort ein. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
|
||||
\item [Reaktion] Der Browser wechselt zum \Gls{dashboard}.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer hat sich erfolgreich angemeldet. Bei der Anmeldung wurde die Option \enquote{Angemeldet bleiben} ausgewählt.
|
||||
\item [Aktion] Der Benutzer startet seinen Browser neu. Dann gibt er die URL der Weboberfläche in der Kopfzeile ein und drückt Enter.
|
||||
\item [Reaktion] Der Benutzer wird automatisch angemeldet und das
|
||||
\Gls{dashboard} geladen.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer hat sich erfolgreich angemeldet. Bei der Anmeldung wurde die nicht Option \enquote{Angemeldet bleiben} ausgewählt.
|
||||
\item [Aktion] Der Benutzer startet seinen Browser neu. Dann gibt er die URL der Weboberfläche in der Kopfzeile ein und drückt Enter.
|
||||
\item [Reaktion] Der Browser wechselt zur Anmeldeseite. Der Benutzer wird nicht automatisch angemeldet.\\
|
||||
\end{description}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
|
||||
|
||||
\subsection{Passwort ändern}\label{t:change-pw}
|
||||
\vspace{0.3cm}
|
||||
|
||||
\begin{description}
|
||||
\item [Vorbedingung] Es gibt einen Benutzer mit der E-Mail \enquote{pseIstToll@test.com} und dem Passwort \enquote{Test123!?}.
|
||||
\end{description}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist angemeldet. Das \Gls{dashboard} ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer klickt auf den Profil-Knopf oben rechts (Pfeil nach unten neben dem Männchen). Dann klickt er in dem geöffneten Menu oben rechts auf den Knopf \enquote{Einstellungen}.
|
||||
\item [Reaktion] Der Browser wechselt zur \enquote{Einstellungs}-Oberfläche.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist angemeldet. Die \enquote{Einstellungs}-Oberfläche ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer macht keine Eingaben und klickt auf den Knopf \enquote{Passwort ändern}.
|
||||
\item [Reaktion] Die \enquote{Einstellungs}-Oberfläche bleibt geladen. Der Benutzer wird aufgefordert die Felder \enquote{Altes Passwort}, \enquote{Neues Passwort} und \enquote{Wiederholen} auszufüllen.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist angemeldet. Die \enquote{Einstellungs}-Oberfläche ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{test} als altes Passwort ein. Weiter gibt er in die Felder \enquote{Neues Passwort} und \enquote{Wiederholen} \enquote{NeuerTest123!?} ein. Dann klickt er auf den Knopf \enquote{Passwort ändern}.
|
||||
\item [Reaktion] Die \enquote{Einstellungs}-Oberfläche bleibt geladen. Der Benutzer bekommt eine Fehlermeldung, dass das alte Passwort falsch ist. In den Feldern \enquote{Neues Passwort} und \enquote{Wiederholen} steht weiter \enquote{NeuerTest123!?}.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist angemeldet. Die \enquote{Einstellungs}-Oberfläche ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{Test123!?} als altes Passwort ein. Weiter gibt er in die Felder \enquote{Neues Passwort} und \enquote{Wiederholen} \enquote{neuerTest} ein. Dann klickt er auf den Knopf \enquote{Passwort ändern}.
|
||||
\item [Reaktion] Die \enquote{Einstellungs}-Oberfläche bleibt geladen. Dem Benutzer wird angezeigt das sein neues Passwort nicht die Passwort-Mindestanforderungen erfüllt. Weiter wird farblich angezeigt, dass sein Passwort nicht:
|
||||
\color{red}
|
||||
\begin{itemize}
|
||||
\item mindestens eine Zahl enthält.
|
||||
\item mindestens ein Sonderzeichen enthält.
|
||||
\end{itemize}
|
||||
\color{black}
|
||||
Dem Benutzer wird farblich angezeigt, dass sein Passwort:
|
||||
\color{ForestGreen}
|
||||
\begin{itemize}
|
||||
\item mindestens 8 Zeichen lang ist.
|
||||
\item mindestens einen Kleinbuchstaben enthält.
|
||||
\item mindestens einen Großbuchstaben enthält.
|
||||
\end{itemize}
|
||||
\color{black}
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist angemeldet. Die \enquote{Einstellungs}-Oberfläche ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt in das \enquote{Altes Passwort}-Feld \enquote{Test123!?} ein. Er gibt in das \enquote{Neues Passwort}-Feld und in das \enquote{Wiederholen}-Feld \enquote{NeuerTest123!?} ein. Dann klickt er auf den Knopf \enquote{Passwort ändern}.
|
||||
\item [Reaktion] Die \enquote{Einstellungs}-Oberfläche bleibt geladen. Die Felder \enquote{Altes Passwort}, \enquote{Neues Passwort} und \enquote{Wiederholen} werden geleert. Dem Benutzer wird angezeigt, dass das Passwort erfolgreich geändert wurde.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist angemeldet. Die \enquote{Einstellungs}-Oberfläche ist im Browser geladen. Sein Passwort wurde zu \enquote{NeuerTest123!?} geändert.
|
||||
\item [Aktion] Der Benutzer meldet sich ab.
|
||||
\item [Reaktion] Der Browser wechselt zur Anmeldeseite. Der Benutzer ist abgemeldet.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist abgemeldet. Die Anmeldeseite ist geladen.
|
||||
\item [Aktion] Der Benutzer gibt als E-Mail \enquote{pseIstToll@test.com} und \enquote{Test123!?} als Passwort ein. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
|
||||
\item [Reaktion] Die Anmeldeseite bleibt geladen. Als E-Mail ist \enquote{pseIstToll@test.com} eingetragen und als Passwort ist \enquote{Test123!?} eingetragen. Dem Benutzer wird per Fehlermeldung ausgegeben, dass E-Mail-Adresse oder Passwort ungültig sind.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist abgemeldet. Die Anmeldeseite ist geladen.
|
||||
\item [Aktion] Der Benutzer gibt als E-Mail \enquote{pseIstToll@test.com} und \enquote{NeuerTest123!?} als Passwort ein. Dann klickt der Benutzer auf den Knopf \enquote{Anmelden}.
|
||||
\item [Reaktion] Der Browser wechselt zum \Gls{dashboard}.\\
|
||||
\end{description}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
|
||||
|
||||
\subsection{Passwort vergessen}\label{t:forgot-pw}
|
||||
\vspace{0.3cm}
|
||||
|
||||
\begin{description}
|
||||
\item [Vorbedingung] Es gibt nur einen registrierten Benutzer. Dieser hat die E-Mail \enquote{pseIstToll@test.com} und \enquote{Test123!?} als Passwort.
|
||||
\end{description}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Anmeldeseite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer klickt auf den Knopf \enquote{Passwort vergessen?}.
|
||||
\item [Reaktion] Der Browser wechselt zur \enquote{Passwort vergessen}-Seite.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Passwort-Vergessen-Seite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstSuperToll@test.com} ein. Dann klickt der Benutzer auf den Knopf \enquote{Bestätigen}.
|
||||
\item [Reaktion] Die \enquote{Passwort zurücksetzen}-Seite bleibt geladen. Dem Benutzer wird eine Fehlermeldung angezeigt, dass diese E-Mail-Adresse nicht vergeben ist.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Passwort-Vergessen-Seite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstToll@test.com} ein. Der Benutzer klickt auf den Knopf \enquote{Bestätigen}.
|
||||
\item [Reaktion] Der Benutzer wird darüber benachrichtigt, dass an die angegebene E-Mail-Adresse eine E-Mail mit einem Link zum Zurücksetzen des Passworts versendet wurde.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer hat die E-Mail mit dem Link zum Zurücksetzen des Passworts erhalten und sein Passwort noch nicht zurückgesetzt.
|
||||
\item [Aktion] Der Benutzer klickt innerhalb von 24 Stunden nach Versendung auf den Link zum Passwort Zurücksetzen.
|
||||
\item [Reaktion] Der Browser wechselt zur \enquote{Passwort zurücksetzen}-Seite.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Im Browser ist die \enquote{Passwort zurücksetzen}-Seite geladen.
|
||||
\item [Aktion] Der Benutzer gibt in die Felder \enquote{Neues Passwort} und \enquote{Wiederholen} \enquote{neuerTest} ein. Dann klickt er auf den Knopf \enquote{Passwort zurücksetzen}.
|
||||
\item [Reaktion] Die \enquote{Passwort zurücksetzen}-Seite bleibt geladen. Dem Benutzer wird angezeigt das sein neues Passwort nicht die Passwort-Mindestanforderungen erfüllt. Weiter wird farblich angezeigt, dass sein Passwort nicht:
|
||||
\color{red}
|
||||
\begin{itemize}
|
||||
\item mindestens eine Zahl enthält.
|
||||
\item mindestens ein Sonderzeichen enthält.
|
||||
\end{itemize}
|
||||
\color{black}
|
||||
Dem Benutzer wird farblich angezeigt, dass sein Passwort:
|
||||
\color{ForestGreen}
|
||||
\begin{itemize}
|
||||
\item mindestens 8 Zeichen lang ist.
|
||||
\item mindestens einen Kleinbuchstaben enthält.
|
||||
\item mindestens einen Großbuchstaben enthält.
|
||||
\end{itemize}
|
||||
\color{black}
|
||||
\end{description}
|
||||
|
||||
\newpage
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Im Browser ist die \enquote{Passwort zurücksetzen}-Seite geladen.
|
||||
\item [Aktion] Der Benutzer gibt in das \enquote{Neues Passwort}-Feld und in das \enquote{Wiederholen}-Feld \enquote{NeuerTest123!?} ein. Dann klickt der Benutzer auf den Knopf \enquote{Passwort zurücksetzen}.
|
||||
\item [Reaktion] Der Browser wechselt zur Anmeldeseite. Der verwendete Link zum zurücksetzen des Passworts wird ungültig.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Im Browser ist die Anmeldeseite geladen.
|
||||
\item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstToll@test.com} und \enquote{Test\-123!?} als Passwort ein.
|
||||
\item [Reaktion] Die Anmeldeseite bleibt geladen. Der Benutzer bekommt eine Fehlermeldung, dass die E-Mail oder das Passwort ungültig ist.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Im Browser ist die Anmeldeseite geladen.
|
||||
\item [Aktion] Der Benutzer gibt in das \enquote{E-Mail}-Feld \enquote{pseIstToll@test.com} und \enquote{NeuerTest123!?} als Passwort ein.
|
||||
\item [Reaktion] Der Browser wechselt zum \Gls{dashboard}.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer hat die E-Mail mit dem Link zum Zurücksetzen des Passworts erhalten und sein Passwort noch nicht zurückgesetzt. Die E-Mail wurde vor mehr als 24 Stunden versendet.
|
||||
\item [Aktion] Der Benutzer klickt auf den Link zum Passwort Zurücksetzen.
|
||||
\item [Reaktion] Der Benutzer bekommt eine Fehlermeldung, dass der Link abgelaufen ist. Das Passwort wird nicht zurückgesetzt. Der Benutzer wird auf die Anmeldeseite weitergeleitet.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer hat die E-Mail mit dem Link zum Zurücksetzen des Passworts erhalten und sein Passwort bereits über diesen Link zurückgesetzt.
|
||||
\item [Aktion] Der Benutzer klickt erneut auf den Link zum Passwort Zurücksetzen.
|
||||
\item [Reaktion] Der Benutzer bekommt eine Fehlermeldung, dass der Link abgelaufen ist. Das Passwort wird nicht zurückgesetzt. Der Benutzer wird auf die Anmeldeseite weitergeleitet.\\
|
||||
\end{description}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
|
||||
|
||||
\subsection{Account Löschen}\label{t:delete-acc}
|
||||
\vspace{0.3cm}
|
||||
|
||||
\begin{description}
|
||||
\item [Vorbedingung] Es gibt den registrierten Benutzer mit der E-Mail \enquote{pseIstToll@test.com} und \enquote{Test123!?} als Passwort.
|
||||
\end{description}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist angemeldet. Im Browser ist die Einstellungsseite geladen. Möglichkeit zum Löschen des Accounts unten links.
|
||||
\item [Aktion] Der Benutzer klickt auf den Knopf \enquote{Account löschen}.
|
||||
\item [Reaktion] Der Browser wechselt zur Account-Löschen-Seite. Auf dieser wird der Benutzer aufgefordert sein Passwort einzugeben um den Vorgang des Löschens zu Bestätigen.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Account-Löschen-Seite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer macht keine Eingaben und klickt auf den Knopf \enquote{Account löschen bestätigen}.
|
||||
\item [Reaktion] Die Account-Löschen-Seite bleibt geladen. Dem Benutzer wird eine Fehlermeldung angezeigt, dass er um die Account Löschung zu bestätigen sein Passwort eingeben muss.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Account-Löschen-Seite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{test123!?} als Passwort ein und klickt auf den Knopf \enquote{Account löschen bestätigen}.
|
||||
\item [Reaktion] Es bleibt die Account-Löschen-Seite geladen. Dem Benutzer wird eine Fehlermeldung angezeigt, dass das Passwort falsch ist.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Account-Löschen-Seite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt \enquote{Test123!?} als Passwort ein und klickt auf den Knopf \enquote{Account löschen bestätigen}.
|
||||
\item [Reaktion] Der Account des Benutzers wird zusammen mit allen dazugehörigen gespeicherten Daten gelöscht. Der Browser wechselt zur Anmeldeseite.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Anmeldeseite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer gibt als E-Mail \enquote{pseIstToll@test.com} und \enquote{Test123!?} als Passwort ein. Dann klickt er auf den \enquote{Anmelden} Knopf.
|
||||
\item [Reaktion] Die Anmeldeseite bleibt geladen und dem Benutzer wird eine Fehlermeldung angezeigt: \enquote{E-Mail-Adresse oder Passwort ist ungültig!}
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die Account-Löschen-Seite ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer klickt auf den \enquote{Abbrechen} Knopf.
|
||||
\item [Reaktion] Der Account wird nicht gelöscht. Der Browser wechselt zur Einstellungsseite.
|
||||
\end{description}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
|
||||
|
||||
\subsection{Synchronisation: Podcast abonnieren}\label{t:sync-sub}
|
||||
\vspace{0.3cm}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist in einem synchronisierten \Gls{podcatcher} angemeldet.
|
||||
\item [Aktion] Der Benutzer fügt den \Gls{podcast} \enquote{Der tagesschau
|
||||
Zukunfts-Podcast: mal angenommen} zu seinen \Glspl{abo} hinzu.
|
||||
\item [Reaktion] Der \Gls{podcatcher} synchronisiert das neue \Gls{abo}.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Dem Benutzer wird die \enquote{Zuletzt gehört}-Oberfläche angezeigt.
|
||||
\item [Aktion] Der Benutzer klickt auf den Reiter \enquote{Podcasts}.
|
||||
\item [Reaktion] Der Browser wechselt zur \enquote{Podcasts}-Oberfläche.
|
||||
Diese zeigt eine Liste aller abonnierten \Glspl{podcast}. Der oberste
|
||||
Eintrag ist der \Gls{podcast} \enquote{Der tagesschau Zukunfts-Podcast:
|
||||
mal angenommen}.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer meldet sich über ein anderes Gerät in einem
|
||||
synchronisierten \Gls{podcatcher} an.
|
||||
\item [Aktion] Der Benutzer lässt sich im \Gls{podcatcher} die Liste seiner
|
||||
\Glspl{abo} anzeigen.
|
||||
\item [Reaktion] Nach kurzer Zeit oder durch manuelles Synchronisieren wird
|
||||
dem Benutzer dort ebenfalls die aktualisierte Liste der \Glspl{abo}
|
||||
angezeigt. Diese enthält insbesondere den Eintrag mit dem \Gls{podcast} \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen}.\\
|
||||
\end{description}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
\subsection{Synchronisation: Podcast deabonnieren}\label{t:sync-unsub}
|
||||
\vspace{0.3cm}
|
||||
|
||||
\begin{description}
|
||||
\item [Vorbedingung] Der Benutzer hat den \Gls{podcast} \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen} abonniert.
|
||||
\end{description}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist in einem synchronisierten \Gls{podcatcher} angemeldet.
|
||||
\item [Aktion] Der Benutzer deabonniert den \Gls{podcast} \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen}.
|
||||
\item [Reaktion] Der \Gls{podcatcher} synchronisiert die reduzierte Liste
|
||||
der \Glspl{abo}.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die \enquote{Zuletzt gehört}-Oberfläche ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer klickt auf den Reiter \enquote{Podcasts}.
|
||||
\item [Reaktion] Der Browser wechselt zur \enquote{Podcasts}-Oberfläche.
|
||||
Diese zeigt die aktuelle Liste aller abonnierten \Glspl{podcast}. Der Eintrag \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen} ist nicht mehr in der Liste enthalten.\\
|
||||
\end{description}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
|
||||
\subsection{Synchronisation: \Gls{episode} anhören}\label{t:sync-episode}
|
||||
\vspace{0.3cm}
|
||||
|
||||
\begin{enumerate}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist in einem synchronisierten \Gls{podcatcher} angemeldet.
|
||||
\item [Aktion] Der Benutzer hört sich die \Gls{episode} \enquote{Kein Handel mit
|
||||
China? Was dann?} des \Glspl{podcast} \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen} bis zum Zeitpunkt 7 Minuten 19 Sekunden an. Dann beendet er die Wiedergabe.
|
||||
\item [Reaktion] Der \Gls{podcatcher} synchronisiert den Fortschritt beim
|
||||
Anhören der \Gls{episode}.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die \enquote{Podcasts}-Oberfläche ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer klickt auf den Reiter \enquote{Zuletzt gehört}.
|
||||
\item [Reaktion] Der Browser wechselt zur \enquote{Zuletzt
|
||||
gehört}-Oberfläche. Diese zeigt eine Liste aller angefangenen, aber
|
||||
nicht beendeten \Glspl{episode} mit korrespondierendem Hörfortschritt
|
||||
an. Die Liste ist nach der Aktualität des Anhörens oder Ansehens einer
|
||||
\Gls{episode} sortiert. Der oberste Eintrag ist die \Gls{episode} \enquote{Kein Handel mit China? Was dann?} mit dem Fortschritt 7 Minuten 19 Sekunden.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer meldet sich über ein anderes Gerät in einem
|
||||
synchronisierten \Gls{podcatcher} an.
|
||||
\item [Aktion] Der Benutzer hört sich die \Gls{episode} \enquote{Kein Handel mit
|
||||
China? Was dann?} des \Glspl{podcast} \enquote{Der tagesschau Zukunfts-Podcast: mal angenommen} bis zum Zeitpunkt 4 Minuten 30 Sekunden an. Dann beendet er die Wiedergabe.
|
||||
\item [Reaktion] Der \Gls{podcatcher} synchronisiert den Fortschritt beim
|
||||
Anhören der \Gls{episode}.
|
||||
\end{description}
|
||||
|
||||
\item
|
||||
\begin{description}
|
||||
\item [Stand] Die \enquote{Podcasts}-Oberfläche ist im Browser geladen.
|
||||
\item [Aktion] Der Benutzer klickt auf den Reiter \enquote{Zuletzt gehört}.
|
||||
\item [Reaktion] Der Browser wechselt zur \enquote{Zuletzt
|
||||
gehört}-Oberfläche. Der oberste Eintrag der \enquote{Zuletzt
|
||||
gehört}-Liste ist die \Gls{episode} \enquote{Kein Handel mit China? Was dann?} mit dem Fortschritt 4 Minuten 30 Sekunden.\\
|
||||
\end{description}
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
\subsection{Benutzeranleitung anzeigen}\label{t:man}
|
||||
\vspace{0.3cm}
|
||||
|
||||
\begin{description}
|
||||
\item [Stand] Der Benutzer ist im Webfrontend angemeldet.
|
||||
\item [Aktion] Der Benutzer klickt auf den \enquote{Hilfe}-Button oben rechts (Abbildung \ref{fig:help-desktop}).
|
||||
\item [Reaktion] Dem Benutzer wird ein leeres \enquote{Hilfe}-Fenster
|
||||
angezeigt. (Dieses kann nachträglich um Hilfestellungen zum
|
||||
Synchronisieren von \Glspl{podcast} ergänzt werden. \ref{r:no-man})\\
|
||||
\end{description}
|
||||
|
||||
|
||||
\subsection{Lasttest}\label{t:lasttest}
|
||||
\vspace{0.3cm}
|
||||
Es werden Lasttests zur Überprüfung der Leitungsfähigkeit des Synchronisa\-tions-Server Systems durchgeführt.
|
||||
Dabei müssen über einen längeren Zeitraum mindestens 50 Anfragen pro Sekunde verarbeitet werden.
|
||||
Die Antwortzeit pro Anfrage darf dabei nicht mehr als 500 Millisekunden betragen.
|
||||
Der Test gilt als bestanden, wenn diese Anforderungen erfüllt sind.
|
||||
|
5377
00-pflichtenheft/tikz-uml.sty
Normal file
75
00-pflichtenheft/titlepage.tex
Normal file
|
@ -0,0 +1,75 @@
|
|||
%% Encoding: UTF-8 %%
|
||||
|
||||
%% titlepage.tex
|
||||
|
||||
\def\usesf{}
|
||||
\let\usesf\sffamily % diese Zeile auskommentieren für normalen TeX Font
|
||||
|
||||
\begin{titlepage}
|
||||
|
||||
\setlength{\unitlength}{1pt}
|
||||
\begin{picture}(00,0)(70,770)
|
||||
\includegraphics[width=\paperwidth]{assets/KIT_Deckblatt.pdf}
|
||||
\end{picture}
|
||||
|
||||
\thispagestyle{empty}
|
||||
|
||||
\begin{center}
|
||||
\hbox{}
|
||||
\vfill
|
||||
\includegraphics[width=.5\textwidth]{assets/logo.pdf}
|
||||
\vskip 1cm
|
||||
{\usesf
|
||||
{\huge\bfseries PSE\textsuperscript{2} - Podcast Synchronisation \\
|
||||
made Efficient\\
|
||||
Pflichtenheft \par}
|
||||
\vskip 1.8cm
|
||||
{\Large Wintersemester 2022/2023\\}
|
||||
%von\\[2mm]
|
||||
\vskip 1.5cm
|
||||
|
||||
% {\large\bfseries Vorname Nachname\\}
|
||||
% \vskip 1.2cm
|
||||
Praxis der Softwareentwicklung \\
|
||||
Prof. Dr.-Ing. Gregor Snelting \\
|
||||
Fakultät für Informatik\\
|
||||
Karlsruher Institut für Technologie\\
|
||||
\vskip 1.5cm
|
||||
\begin{tabular}{p{20mm}l}
|
||||
Autoren:
|
||||
& Daniel Hönlinger \\
|
||||
& Gero Beckmann \\
|
||||
& Immanuel Reitz \\
|
||||
& Julius Friesen \\
|
||||
& Lukas Schmidheissler \\
|
||||
\\
|
||||
Betreuer: & M.Sc. Hans-Peter Lehmann \\
|
||||
& M.Sc. Daniel Seemaier
|
||||
\end{tabular}
|
||||
}
|
||||
\end{center}
|
||||
\vfill
|
||||
|
||||
%\begin{textblock}{10}[0,0](4,15)
|
||||
% \includegraphics[width=.3\textwidth]{logos/logo.pdf}
|
||||
%\end{textblock}
|
||||
|
||||
% \begin{textblock}{8}[0,0](14,14)
|
||||
% \includegraphics[width=.3\textwidth]{logos/KASTEL_logo.pdf}
|
||||
% \end{textblock}
|
||||
|
||||
\end{titlepage}
|
||||
|
||||
% \thispagestyle{empty}
|
||||
% \ \vfill
|
||||
% \begin{flushleft}
|
||||
% Copyright $\copyright$ ITI und Verfasser 201?\\
|
||||
% \ \\
|
||||
% Institut für Theoretische Informatik
|
||||
% Fakultät für Informatik\\
|
||||
% Karlsruher Institut für Technologie\\
|
||||
% Am Fasanengarten 5\\
|
||||
% 76131 Karlsruhe
|
||||
% \end{flushleft}
|
||||
% \newpage
|
||||
|
302
01-pflichtenheft-kolloquium/.gitignore
vendored
Normal file
|
@ -0,0 +1,302 @@
|
|||
## Core latex/pdflatex auxiliary files:
|
||||
*.aux
|
||||
*.lof
|
||||
*.log
|
||||
*.lot
|
||||
*.fls
|
||||
*.out
|
||||
*.toc
|
||||
*.fmt
|
||||
*.fot
|
||||
*.cb
|
||||
*.cb2
|
||||
.*.lb
|
||||
|
||||
## Intermediate documents:
|
||||
*.dvi
|
||||
*.xdv
|
||||
*-converted-to.*
|
||||
# these rules might exclude image files for figures etc.
|
||||
# *.ps
|
||||
# *.eps
|
||||
*.pdf
|
||||
!assets/*.pdf
|
||||
|
||||
## Generated if empty string is given at "Please type another file name for output:"
|
||||
.pdf
|
||||
|
||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||
*.bbl
|
||||
*.bcf
|
||||
*.blg
|
||||
*-blx.aux
|
||||
*-blx.bib
|
||||
*.run.xml
|
||||
|
||||
## Build tool auxiliary files:
|
||||
*.fdb_latexmk
|
||||
*.synctex
|
||||
*.synctex(busy)
|
||||
*.synctex.gz
|
||||
*.synctex.gz(busy)
|
||||
*.pdfsync
|
||||
|
||||
## Build tool directories for auxiliary files
|
||||
# latexrun
|
||||
latex.out/
|
||||
|
||||
## Auxiliary and intermediate files from other packages:
|
||||
# algorithms
|
||||
*.alg
|
||||
*.loa
|
||||
|
||||
# achemso
|
||||
acs-*.bib
|
||||
|
||||
# amsthm
|
||||
*.thm
|
||||
|
||||
# beamer
|
||||
*.nav
|
||||
*.pre
|
||||
*.snm
|
||||
*.vrb
|
||||
|
||||
# changes
|
||||
*.soc
|
||||
|
||||
# comment
|
||||
*.cut
|
||||
|
||||
# cprotect
|
||||
*.cpt
|
||||
|
||||
# elsarticle (documentclass of Elsevier journals)
|
||||
*.spl
|
||||
|
||||
# endnotes
|
||||
*.ent
|
||||
|
||||
# fixme
|
||||
*.lox
|
||||
|
||||
# feynmf/feynmp
|
||||
*.mf
|
||||
*.mp
|
||||
*.t[1-9]
|
||||
*.t[1-9][0-9]
|
||||
*.tfm
|
||||
|
||||
#(r)(e)ledmac/(r)(e)ledpar
|
||||
*.end
|
||||
*.?end
|
||||
*.[1-9]
|
||||
*.[1-9][0-9]
|
||||
*.[1-9][0-9][0-9]
|
||||
*.[1-9]R
|
||||
*.[1-9][0-9]R
|
||||
*.[1-9][0-9][0-9]R
|
||||
*.eledsec[1-9]
|
||||
*.eledsec[1-9]R
|
||||
*.eledsec[1-9][0-9]
|
||||
*.eledsec[1-9][0-9]R
|
||||
*.eledsec[1-9][0-9][0-9]
|
||||
*.eledsec[1-9][0-9][0-9]R
|
||||
|
||||
# glossaries
|
||||
*.acn
|
||||
*.acr
|
||||
*.glg
|
||||
*.glo
|
||||
*.gls
|
||||
*.glsdefs
|
||||
*.lzo
|
||||
*.lzs
|
||||
*.slg
|
||||
*.slo
|
||||
*.sls
|
||||
|
||||
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
||||
*.ist
|
||||
|
||||
# gnuplot
|
||||
*.gnuplot
|
||||
*.table
|
||||
|
||||
# gnuplottex
|
||||
*-gnuplottex-*
|
||||
|
||||
# gregoriotex
|
||||
*.gaux
|
||||
*.glog
|
||||
*.gtex
|
||||
|
||||
# htlatex
|
||||
*.4ct
|
||||
*.4tc
|
||||
*.idv
|
||||
*.lg
|
||||
*.trc
|
||||
*.xref
|
||||
|
||||
# hyperref
|
||||
*.brf
|
||||
|
||||
# knitr
|
||||
*-concordance.tex
|
||||
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
|
||||
# *.tikz
|
||||
*-tikzDictionary
|
||||
|
||||
# listings
|
||||
*.lol
|
||||
|
||||
# luatexja-ruby
|
||||
*.ltjruby
|
||||
|
||||
# makeidx
|
||||
*.idx
|
||||
*.ilg
|
||||
*.ind
|
||||
|
||||
# minitoc
|
||||
*.maf
|
||||
*.mlf
|
||||
*.mlt
|
||||
*.mtc[0-9]*
|
||||
*.slf[0-9]*
|
||||
*.slt[0-9]*
|
||||
*.stc[0-9]*
|
||||
|
||||
# minted
|
||||
_minted*
|
||||
*.pyg
|
||||
|
||||
# morewrites
|
||||
*.mw
|
||||
|
||||
# newpax
|
||||
*.newpax
|
||||
|
||||
# nomencl
|
||||
*.nlg
|
||||
*.nlo
|
||||
*.nls
|
||||
|
||||
# pax
|
||||
*.pax
|
||||
|
||||
# pdfpcnotes
|
||||
*.pdfpc
|
||||
|
||||
# sagetex
|
||||
*.sagetex.sage
|
||||
*.sagetex.py
|
||||
*.sagetex.scmd
|
||||
|
||||
# scrwfile
|
||||
*.wrt
|
||||
|
||||
# svg
|
||||
svg-inkscape/
|
||||
|
||||
# sympy
|
||||
*.sout
|
||||
*.sympy
|
||||
sympy-plots-for-*.tex/
|
||||
|
||||
# pdfcomment
|
||||
*.upa
|
||||
*.upb
|
||||
|
||||
# pythontex
|
||||
*.pytxcode
|
||||
pythontex-files-*/
|
||||
|
||||
# tcolorbox
|
||||
*.listing
|
||||
|
||||
# thmtools
|
||||
*.loe
|
||||
|
||||
# TikZ & PGF
|
||||
*.dpth
|
||||
*.md5
|
||||
*.auxlock
|
||||
|
||||
# titletoc
|
||||
*.ptc
|
||||
|
||||
# todonotes
|
||||
*.tdo
|
||||
|
||||
# vhistory
|
||||
*.hst
|
||||
*.ver
|
||||
|
||||
# easy-todo
|
||||
*.lod
|
||||
|
||||
# xcolor
|
||||
*.xcp
|
||||
|
||||
# xmpincl
|
||||
*.xmpi
|
||||
|
||||
# xindy
|
||||
*.xdy
|
||||
|
||||
# xypic precompiled matrices and outlines
|
||||
*.xyc
|
||||
*.xyd
|
||||
|
||||
# endfloat
|
||||
*.ttt
|
||||
*.fff
|
||||
|
||||
# Latexian
|
||||
TSWLatexianTemp*
|
||||
|
||||
## Editors:
|
||||
# WinEdt
|
||||
*.bak
|
||||
*.sav
|
||||
|
||||
# Texpad
|
||||
.texpadtmp
|
||||
|
||||
# LyX
|
||||
*.lyx~
|
||||
|
||||
# Kile
|
||||
*.backup
|
||||
|
||||
# gummi
|
||||
.*.swp
|
||||
|
||||
# KBibTeX
|
||||
*~[0-9]*
|
||||
|
||||
# TeXnicCenter
|
||||
*.tps
|
||||
|
||||
# auto folder when using emacs and auctex
|
||||
./auto/*
|
||||
*.el
|
||||
|
||||
# expex forward references with \gathertags
|
||||
*-tags.tex
|
||||
|
||||
# standalone packages
|
||||
*.sta
|
||||
|
||||
# Makeindex log files
|
||||
*.lpz
|
||||
|
||||
# xwatermark package
|
||||
*.xwm
|
||||
|
||||
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
|
||||
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
|
||||
# Uncomment the next line to have this generated file ignored.
|
||||
#*Notes.bib
|
15
01-pflichtenheft-kolloquium/.gitlab-ci.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
image: texlive/texlive
|
||||
|
||||
pages:
|
||||
script:
|
||||
- mkdir public
|
||||
- make
|
||||
- mv *.pdf public
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
|
||||
|
||||
|
34
01-pflichtenheft-kolloquium/CHANGELOG.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Changelog
|
||||
Alle Änderungen an diesem Projekt werden in dieser Datei dokumentiert.
|
||||
Die Versionsnummern folgt der Syntax in `sdqbeamer.cls`.
|
||||
|
||||
## [2022-05-03 v3.1.3]
|
||||
- Die Breite des Gruppennamens in der Fußzeile kann nun über `\groupnamewidth{}` gesteuert werden
|
||||
- FIX: zweizeilige Fußzeilen haben nun gleichmäßigen vertikalen Abstand (Issue #16 in Gitlab)
|
||||
|
||||
## [2021-08-10 v3.1.2]
|
||||
- FIX: framesubtitle wird nun angezeigt (Issue #6 in Gitlab)
|
||||
|
||||
## [2020-12-08 v3.1.1]
|
||||
- FIX: Titelbild (Issue #4 in Gitlab)
|
||||
|
||||
## [2020-12-07 v3.1]
|
||||
- Umgebung ``contentblock`` (farbloser Block mit fetter Überschrift) hinzugefügt
|
||||
- Farbboxen (``greenblock``, ``blueblock``, …) hinzugefügt
|
||||
- Abstufungen der KIT-Farben in 10er-Schritten entsprechend der Gestaltungsrichtlinien eingeführt
|
||||
- FIX: Navigationspunkte für Subsections in eine Zeile gesetzt, um vertikal Platz zu sparen
|
||||
- FIX: ``inputenc`` an den Anfang von ``sdqbeamer.cls`` verschoben
|
||||
|
||||
## [2020-11-16 v3.0]
|
||||
- Seitenformat 16:10 hinzugefügt
|
||||
- Umstellung auf KIT-Design vom 1. August 2020
|
||||
- Anpassung auf neues Farbschema und Maße
|
||||
- neues Titelbild aus der KIT-Bildwelt
|
||||
- Neue Optionen:
|
||||
- durch `smallfoot` und `bigfoot` kann die Schriftgröße der Fußzeile gesteuert werden
|
||||
- durch `navbarkit` kann eine Fußzeile nach KIT-Vorgaben erzwungen werden
|
||||
- Deutsch (`de`) ist nun die Standard-Option
|
||||
- Ordner `templates` wurde gelöscht und die Inhalte in `sdqbeamer.cls` integriert
|
||||
- Globale Größe auf 10 pt verringert (vorher: 11 pt), da der beschreibbare Bereich im Vergleich zur 2009er Version kleiner geworden ist
|
||||
- SDQ-spezifische Logos und Titelbilder entfernt. Diese sind ab sofort im Branch »sdq« verfügbar.
|
||||
- Fix: Zeilenumbruch bei Titel in der Fußzeile repariert
|
10
01-pflichtenheft-kolloquium/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
MAIN = presentation.tex
|
||||
FLAGS = -pdf
|
||||
|
||||
all:
|
||||
latexmk $(FLAGS) $(MAIN)
|
||||
dev:
|
||||
latexmk $(FLAGS) -pvc $(MAIN)
|
||||
clean:
|
||||
latexmk -C
|
||||
|
118
01-pflichtenheft-kolloquium/README.md
Normal file
|
@ -0,0 +1,118 @@
|
|||
LaTeX-Vorlage für Präsentationen
|
||||
================================
|
||||
|
||||
Das vorliegende Paket dient als Vorlage für Präsentationen im [Corporate Design des KIT](https://intranet.kit.edu/gestaltungsrichtlinien.php) (Fassung vom 1. August 2020).
|
||||
|
||||
Es wird an der Forschungsgruppe [DSiS](https://dsis.kastel.kit.edu) an der KIT-Fakultät für Informatik entwickelt und basiert auf [LaTeX Beamer](https://ctan.org/pkg/beamer).
|
||||
|
||||
Autor: [Dr.-Ing. Erik Burger](https://dsis.kastel.kit.edu/staff_erik_burger.php)
|
||||
mit Beiträgen von Christian Hammer, Klaus Krogmann und Maximilian Schambach
|
||||
|
||||
Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
|
||||
|
||||
Hinweise, Verbesserungsvorschläge
|
||||
=================================
|
||||
|
||||
Bitte verwenden Sie das [Issue-Tracking-System von Gitlab](https://git.scc.kit.edu/i43/dokumentvorlagen/praesentationen/beamer/-/issues), um auf Probleme mit der Vorlage hinzuweisen oder Erweiterungswünsche zu äußern. Sie können gerne auch eine Änderung per Merge-Request vorschlagen.
|
||||
|
||||
Verwendung
|
||||
==========
|
||||
|
||||
Optionen der Dokumentklasse `sdqbeamer`
|
||||
-----------------------------------------
|
||||
Durch die folgenden Optionen kann das Seitenverhältnis der Folien bestimmt werden:
|
||||
|
||||
| Seitenverhältnis | Option |
|
||||
| ---------------- | ------------------- |
|
||||
| 16:9 | `16:9` (Standard) |
|
||||
| 16:10 | `16:10` |
|
||||
| 4:3 | `4:3` |
|
||||
|
||||
Die Schriftgröße in der Fußzeile ist standardmäßig größer gewählt, als in den Gestaltungsrichtlinien vorgegeben. Diese Vorgabe kann durch die Option `smallfoot` erzwungen werden.
|
||||
|
||||
| Schriftgröße Fußzeile | Option |
|
||||
| ----------------------| -------------------- |
|
||||
| etwas größer (12pt) | `bigfoot` (Standard) |
|
||||
| KIT-Vorgabe (9pt) | `smallfoot` |
|
||||
|
||||
Die Plazierung der Navigationsleiste kann durch folgende Optionen beeinflußt werden:
|
||||
|
||||
| Position | Option | Bemerkung |
|
||||
| ------------------------ | ---------------- | ------------------------------------------ |
|
||||
| oberhalb der Trennlinie | `navbarinline` | Standard |
|
||||
| unterhalb der Trennlinie | `navbarinfooter` | keine Subsection-Punkte, Größe `smallfoot` |
|
||||
| Seitenleiste links | `navbarside` | keine Subsection-Punkte |
|
||||
| keine Navigationsleiste | `navbaroff` | |
|
||||
| KIT-Vorgabe | `navbarkit` | entspricht `navbaroff` und `smallfoot` |
|
||||
|
||||
Als Sprache sind Deutsch und Englisch verfügbar. Durch die Sprachwahl werden automatisch die passenden Logos und Formate (z.B. Datum) gewählt.
|
||||
|
||||
| Sprache | |
|
||||
| -------- |---------------- |
|
||||
| Deutsch | `de` (Standard) |
|
||||
| Englisch | `en` |
|
||||
|
||||
Beispiel: `\documentclass[de,16:9,navbarinline]{sdqbeamer}`
|
||||
|
||||
Titelbild
|
||||
---------
|
||||
|
||||
Das Bild auf der Titelfolie kann mit dem Befehl
|
||||
|
||||
`\titleimage{myimage}` (ohne Dateiendung)
|
||||
|
||||
gesetzt werden. Um ein eigenes Bild zu verwenden, bitte die Datei (z.B. `myimage.jpg`) ins `logos/`-Verzeichnis legen und den Befehl anpassen. Mitgeliefert wird ein generisches Bild aus der KIT-Bildwelt (https://intranet.kit.edu/gestaltungsrichtlinien.php) in der Datei `logos/banner_2020_kit.jpg`. Falls kein Titelbild eingefügt werden soll, bitte `\titleimage{}` setzen.
|
||||
|
||||
Für 16:9-Folien sollte das Verhältnis des Bildes 160:37 betragen, für 4:3-Folien 63:20. Es können auch breitere Bilder verwendet werden, da das Titelbild auf die Höhe des Rahmens skaliert und zentriert wird.
|
||||
|
||||
Logo und Name Abteilung/KIT-Fakultät/Institut
|
||||
---------------------------------------------
|
||||
|
||||
Das Logo rechts oben auf der Titelfolie kann mit dem folgenden Befehl gesetzt werden:
|
||||
|
||||
`\grouplogo{mylogo}` (ohne Dateiendung)
|
||||
|
||||
Um ein eigenes Logo zu verwenden, bitte die Datei (z.B. `mylogo.pdf`) in das Verzeichnis `logos/` legen und den Befehl anpassen. Falls kein Logo eingefügt werden soll, bitte `\grouplogo{}` setzen.
|
||||
|
||||
Der Gruppenname kann mit folgendem Befehl gesetzt werden:
|
||||
|
||||
`\groupname{Software Design and Quality}`
|
||||
|
||||
Der Gruppenname erscheint in der Fußzeile rechts unten. Lange Namen werden in zwei Zeilen umgebrochen. Falls der Gruppenname leer gelassen wird (`\groupname{}`), wird die volle Breite der Fußzeile für Autornamen und Titel verwendet.
|
||||
|
||||
Die Standardbreite des Gruppennamens sind 50 mm. Sie kann mit
|
||||
|
||||
`\groupnamewidth{80mm}`
|
||||
|
||||
verändert werden, wodurch sich auch die Breite des Textfeldes mit Autor und Titel entsprechend ändert. Umbrüche sind mit `\\` möglich. Statt zweizeiliger Fußzeilen empfiehlt sich eventuell die Option `smallfoot`.
|
||||
|
||||
LaTeX allgemein
|
||||
---------------
|
||||
Siehe https://sdqweb.ipd.kit.edu/wiki/LaTeX
|
||||
|
||||
Dateistruktur
|
||||
============
|
||||
`presentation.tex`
|
||||
------------------
|
||||
Hauptdatei des LaTeX-Dokuments.
|
||||
|
||||
`presentation.bib`
|
||||
-------------
|
||||
Beispieldatei für BibTeX-Referenzen
|
||||
https://sdqweb.ipd.kit.edu/wiki/BibTeX-Literaturlisten
|
||||
|
||||
`sdqbeamer.cls`
|
||||
-----------------
|
||||
Dokumentklasse für Präsentationen im KIT-Design.
|
||||
|
||||
`logos/`
|
||||
--------
|
||||
In diesem Verzeichnis befinden das KIT-Logo als PDF sowie das Hintergrundbild der Titelfolie als JPG.
|
||||
|
||||
`CHANGELOG.md`
|
||||
--------------
|
||||
Dokumentation der Änderungen in den jeweiligen Versionen.
|
||||
|
||||
`README.md`
|
||||
-----------
|
||||
Dieser Text.
|
BIN
01-pflichtenheft-kolloquium/logos/banner_2020_kit.jpg
Normal file
After Width: | Height: | Size: 95 KiB |
40
01-pflichtenheft-kolloquium/notizen
Normal file
|
@ -0,0 +1,40 @@
|
|||
Titelseite:
|
||||
- Begrüßung
|
||||
|
||||
Einführung:
|
||||
- Podcast: RSS-Feed, Episoden, Audio/Video
|
||||
- Podcatcher: lokale Verwaltung von Podcasts, API Unterstützung,
|
||||
Abspielen von Episoden
|
||||
- Synchronisationsserver (das soll unser Produkt werden): Hörfortschritte,
|
||||
Abonnements, Discovery (bei AntennaPod z.B. iTunes)
|
||||
|
||||
Zielsetzung:
|
||||
|
||||
Synchronisation (die Art, die wir bei uns anwenden):
|
||||
- alle Aktionen werden auf den Server und infolge dessen auf alle Podcatcher
|
||||
übertragen
|
||||
|
||||
Features:
|
||||
- Synchronisation: Abos, Hörfortschritt
|
||||
- Weboberfläche: Aboliste, Zuletzt gehört
|
||||
- Account-Verwaltung: Registrieren, Anmelden, Passwort ändern/zurücksetzen,
|
||||
Account löschen, Daten importieren/exportieren
|
||||
|
||||
UI-Journey:
|
||||
- login.html:
|
||||
- Sprache ändern
|
||||
- OAuth (kann)
|
||||
- Registrieren (muss): neues Fenster, E-Mail + 2-mal Passwort (sicher?),
|
||||
vergeben? -> Fehler / Bestätigungslink per E-Mail (gültig 24h)
|
||||
- Anmelden (muss): E-Mail + Passwort eingeben, Login merken,
|
||||
login, Fehlermeldung oder Dashboard
|
||||
- Passwort vergessen: neues Fenster, E-Mail eingeben, falls Account wird
|
||||
Link versendet, 24h gültig, nach betätigen PW zweimal eingeben & bestätigen
|
||||
(Anforderungen)
|
||||
|
||||
- podcasts.html: Abonnements, Eisoden, Hörfortschritte
|
||||
|
||||
- listening.html: Zuletzt gehörte Episoden, Hörfortschritt, Wann gehört
|
||||
|
||||
- settings.html: PW ändern, Gpodder Import, pers. Daten imp./exp.,
|
||||
Account löschen
|
60
01-pflichtenheft-kolloquium/presentation.tex
Normal file
|
@ -0,0 +1,60 @@
|
|||
%% Beispiel-Präsentation mit LaTeX Beamer im KIT-Design
|
||||
%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
|
||||
%%
|
||||
%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
|
||||
|
||||
%% Beispiel-Präsentation
|
||||
\documentclass{sdqbeamer}
|
||||
|
||||
\usepackage{tikz}
|
||||
\usetikzlibrary{positioning}
|
||||
\usetikzlibrary{calc}
|
||||
\usetikzlibrary{arrows}
|
||||
\usepackage{multicol}
|
||||
\usepackage{fontawesome5}
|
||||
\usepackage{tikz}
|
||||
\usepackage{tikz-uml}
|
||||
\usetikzlibrary{positioning, arrows, chains}
|
||||
\usetikzlibrary[calc]
|
||||
|
||||
|
||||
%% Titelbild
|
||||
\titleimage{banner_2020_kit}
|
||||
|
||||
%% Gruppenlogo
|
||||
\grouplogo{kitlogo_de_rgb}
|
||||
|
||||
%% Gruppenname und Breite (Standard: 50 mm)
|
||||
\groupname{Praxis der Softwareentwicklung}
|
||||
%\groupnamewidth{50mm}
|
||||
|
||||
% Beginn der Präsentation
|
||||
|
||||
\title[Kolloquium Pflichtenheft]{
|
||||
PSE\textsuperscript{2} - Podcast Synchronisation made Efficient
|
||||
}
|
||||
\subtitle{Kolloquium Pflichtenheft}
|
||||
\author[Julius Friesen]{Julius Friesen}
|
||||
|
||||
\date[06.\,12.\,2022]{06. Dezember 2022}
|
||||
|
||||
\begin{document}
|
||||
|
||||
%Titelseite
|
||||
\KITtitleframe
|
||||
|
||||
% Folie Einführung
|
||||
\include{slides/einführung}
|
||||
|
||||
% Folie Zielsetzung
|
||||
\include{slides/zielsetzung}
|
||||
|
||||
% TODO: Folie Synchronisation
|
||||
\include{slides/synchronisation}
|
||||
|
||||
% TODO: Folie Features
|
||||
\include{slides/features}
|
||||
|
||||
% TODO: User-Journey
|
||||
|
||||
\end{document}
|
954
01-pflichtenheft-kolloquium/sdqbeamer.cls
Normal file
|
@ -0,0 +1,954 @@
|
|||
%% Vorlage für Präsentationen mit LaTeX Beamer im KIT-Design
|
||||
%% entsprechend den Gestaltungsrichtlinien vom 1. August 2020
|
||||
%%
|
||||
%% Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
|
||||
|
||||
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesClass{sdqbeamer}[2022-05-03 v3.1.3 SDQ Beamer class]
|
||||
|
||||
\RequirePackage[utf8]{inputenc}
|
||||
\RequirePackage[T1]{fontenc}
|
||||
|
||||
\newif\ifsectionnavigation
|
||||
\newif\ifnavbarinfoot
|
||||
\newif\ifnavbarinline
|
||||
\newif\ifnavbarside
|
||||
\newif\iffourtothree
|
||||
\newif\ifsixteentonine
|
||||
\newif\ifsixteentoten
|
||||
\newif\ifgerman
|
||||
\newif\ifsmallfooterfont
|
||||
|
||||
\def\kitslogan#1{\def\@kitslogan{#1}}
|
||||
\def\kitlogo#1{\def\@kitlogo{#1}}
|
||||
\def\groupname#1{\def\@groupname{#1}}
|
||||
\def\groupnamewidth#1{\def\@groupnamewidth{#1}}
|
||||
|
||||
% siehe README.md
|
||||
\DeclareOption{de}{
|
||||
\kitslogan{KIT -- Die Forschungsuniversität in der Helmholtz-Gemeinschaft}
|
||||
\kitlogo{pse_logo}
|
||||
\germantrue
|
||||
\PassOptionsToPackage{autostyle}{csquotes}
|
||||
}
|
||||
\DeclareOption{en}{
|
||||
\kitslogan{KIT -- The Research University in the Helmholtz Association}
|
||||
\kitlogo{kitlogo_en_rgb}
|
||||
\germanfalse
|
||||
}
|
||||
\DeclareOption{4:3}{
|
||||
\fourtothreetrue
|
||||
\sixteentoninefalse
|
||||
\sixteentotenfalse
|
||||
}
|
||||
\DeclareOption{16:9}{
|
||||
\fourtothreefalse
|
||||
\sixteentoninetrue
|
||||
\sixteentotenfalse
|
||||
}
|
||||
\DeclareOption{16:10}{
|
||||
\fourtothreefalse
|
||||
\sixteentoninefalse
|
||||
\sixteentotentrue
|
||||
}
|
||||
\DeclareOption{navbarside}{
|
||||
\sectionnavigationtrue
|
||||
\navbarsidetrue
|
||||
\navbarinlinefalse
|
||||
\navbarinfootfalse
|
||||
}
|
||||
\DeclareOption{navbarinline}{
|
||||
\sectionnavigationtrue
|
||||
\navbarsidefalse
|
||||
\navbarinlinetrue
|
||||
\navbarinfootfalse
|
||||
}
|
||||
\DeclareOption{navbarinfooter}{
|
||||
\sectionnavigationtrue
|
||||
\navbarsidefalse
|
||||
\navbarinlinefalse
|
||||
\navbarinfoottrue
|
||||
}
|
||||
\DeclareOption{navbaroff}{
|
||||
\sectionnavigationfalse
|
||||
}
|
||||
\DeclareOption{navbarkit}{
|
||||
\sectionnavigationfalse
|
||||
\smallfooterfonttrue
|
||||
}
|
||||
\DeclareOption{smallfoot}{
|
||||
\smallfooterfonttrue
|
||||
}
|
||||
\DeclareOption{bigfoot}{
|
||||
\smallfooterfontfalse
|
||||
}
|
||||
|
||||
\ExecuteOptions{de,16:9,navbarinline,bigfoot}
|
||||
|
||||
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{beamer}}
|
||||
|
||||
\ProcessOptions\relax
|
||||
|
||||
\LoadClass[10pt,utf8]{beamer}
|
||||
|
||||
% Babel-Paket wird nur bei deutscher Sprache benötigt
|
||||
\ifgerman
|
||||
\RequirePackage[ngerman]{babel}
|
||||
\fi
|
||||
\RequirePackage{csquotes}
|
||||
\RequirePackage{hyperref}
|
||||
\RequirePackage[absolute,overlay]{textpos}
|
||||
|
||||
%% ---------------
|
||||
%% | Typographie |
|
||||
%% ---------------
|
||||
|
||||
\RequirePackage{microtype}
|
||||
|
||||
\RequirePackage[scaled=.92]{helvet}
|
||||
\RequirePackage[scaled=.78]{beramono}
|
||||
\RequirePackage{libertineRoman}
|
||||
|
||||
\setbeamerfont{title}{series=\bfseries,size=\Large}
|
||||
\setbeamerfont{frametitle}{series=\bfseries,size=\Large}
|
||||
\setbeamerfont{framesubtitle}{series=\bfseries,size=\normalsize}
|
||||
|
||||
%% -----------------
|
||||
%% | Folien-Layout |
|
||||
%% -----------------
|
||||
|
||||
% Seitenverhältnis
|
||||
%
|
||||
% Die Folien sind auf die Standardhöhe in LaTeX Beamer (9,6 cm) normiert.
|
||||
% Die Maße der KIT-Gestaltungsrichtlinien (Folienhöhe 14,3 cm) wurden durch
|
||||
% den Quotienten 1,5 geteilt.
|
||||
|
||||
\RequirePackage{geometry}
|
||||
\iffourtothree
|
||||
\geometry{papersize={12.8cm,9.6cm}}
|
||||
\fi
|
||||
\ifsixteentoten
|
||||
\geometry{papersize={15.36cm,9.6cm}}
|
||||
\fi
|
||||
\ifsixteentonine
|
||||
\geometry{papersize={17.07cm,9.6cm}}
|
||||
\fi
|
||||
|
||||
% Ränder laut Gestaltungsrichtlinen; 3 mm -> 2 mm, 11 mm -> 7,3 mm
|
||||
\newlength{\kitoutermargin}
|
||||
\setlength{\kitoutermargin}{2mm}
|
||||
\newlength{\kitinnermargin}
|
||||
\setlength{\kitinnermargin}{7.3mm}
|
||||
\newlength{\kitbottommargin}
|
||||
\setlength{\kitbottommargin}{\kitinnermargin}
|
||||
|
||||
% Ränder außen
|
||||
\setbeamersize{text margin left=\kitinnermargin,text margin right=\kitinnermargin}
|
||||
|
||||
% keine Navigationssymbole
|
||||
\setbeamertemplate{navigation symbols}{}
|
||||
\setbeamercovered{invisible}
|
||||
\useinnertheme{rounded}
|
||||
\beamer@compresstrue % Miniframes (Navigations-Punkte) für Subsections immer in einer Zeile, ohne Umbrüche
|
||||
|
||||
% Folientitel
|
||||
\setbeamertemplate{frametitle}{
|
||||
\ifbeamer@plainframe\else%
|
||||
% Unterkante Titeltext: 22,5 mm -> 15 mm von Seitenkopf
|
||||
\begin{textblock*}{\dimexpr\paperwidth-30mm-2\kitinnermargin}[0,1](\kitinnermargin,15mm)%
|
||||
\usebeamerfont{frametitle}\insertframetitle%
|
||||
\ifx\insertframesubtitle\@empty\else\\[.1em]\fi
|
||||
\usebeamerfont{framesubtitle}\insertframesubtitle%
|
||||
\end{textblock*}%
|
||||
\begin{textblock*}{20mm}[1,1](\dimexpr\paperwidth-\kitinnermargin\relax,15mm)%j
|
||||
\includegraphics[width=20mm]{logos/\@kitlogo}%
|
||||
\end{textblock*}%
|
||||
\fi
|
||||
% Rand oben (ergibt Beginn des Textes bei 34 mm -> 22,7 mm)
|
||||
\vspace {18mm}
|
||||
}
|
||||
|
||||
%% Fußzeile
|
||||
\newlength{\kitbottom}
|
||||
% Navbar in Footer: Schmale Fußzeile
|
||||
\ifnavbarinfoot
|
||||
% Bei Navbar in Footer immer kleiner Font in der Fußzeile
|
||||
\setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont}
|
||||
\setlength{\kitbottom}{4mm}
|
||||
\else
|
||||
% Ansonsten kleiner Text nur, wenn "smallfoot" gewählt
|
||||
\ifsmallfooterfont
|
||||
\setbeamerfont{footer}{size=\fontsize{6pt}{7.2pt}\selectfont}
|
||||
\else
|
||||
\setbeamerfont{footer}{size=\scriptsize}
|
||||
\fi
|
||||
\setlength{\kitbottom}{\kitbottommargin}
|
||||
\fi
|
||||
\setbeamerfont{page number in head/foot}{series=\bfseries}
|
||||
|
||||
\newlength{\kitbottomdepth}
|
||||
\newlength{\kitbottomheight}
|
||||
\newlength{\kitfootergroupwidth}
|
||||
|
||||
\setbeamertemplate{footline}{%
|
||||
\setlength{\kitbottomdepth}{\dimexpr.5\kitbottom-.5em\relax}%
|
||||
\setlength{\kitbottomheight}{\dimexpr.5\kitbottom+.5em\relax}%
|
||||
%% die "%" am Ende sind nötig, damit keine Abstände eingefügt werden
|
||||
%
|
||||
% Falls kein Gruppenname angegeben, die ganze Breite der Fußzeile für den Titel nutzen.
|
||||
\ifdefined\@groupname%
|
||||
\ifx\@groupname\empty%
|
||||
\setlength{\kitfootergroupwidth}{0mm}%
|
||||
\else%
|
||||
% Falls die Breite des Gruppenlogos definiert ist, diese nehmen, sonst 50 mm
|
||||
\ifdefined\@groupnamewidth%
|
||||
\setlength{\kitfootergroupwidth}{\@groupnamewidth}%
|
||||
\else%
|
||||
\setlength{\kitfootergroupwidth}{50mm}%
|
||||
\fi%
|
||||
\fi%
|
||||
\else
|
||||
\setlength{\kitfootergroupwidth}{0mm}%
|
||||
\fi
|
||||
\usebeamerfont{footer}%
|
||||
\ifsectionnavigation%
|
||||
% Option "navbarinline"
|
||||
\ifnavbarinline%
|
||||
\begin{beamercolorbox}[wd=\paperwidth, leftskip=2mm, rightskip=2mm]{}
|
||||
\insertnavigation{\dimexpr\paperwidth-4mm\relax}
|
||||
\vspace{1mm}
|
||||
\end{beamercolorbox}%
|
||||
\fi%
|
||||
% Option "navbarinfooter"
|
||||
\ifnavbarinfoot%
|
||||
% Punkte für Subsections deaktivieren
|
||||
\setbeamertemplate{mini frames}{}%
|
||||
\begin{beamercolorbox}[wd=\paperwidth, leftskip=1mm, rightskip=1mm]{}%
|
||||
\insertsectionnavigationhorizontal{\dimexpr\paperwidth-\kitoutermargin\relax}{}{}
|
||||
\end{beamercolorbox}%
|
||||
\fi%
|
||||
\fi%
|
||||
\leavevmode%
|
||||
\begin{beamercolorbox}[wd=13mm, ht=\kitbottomheight, dp=\kitbottomdepth, leftskip=4mm]{}
|
||||
\usebeamerfont{page number in head/foot}%
|
||||
\strut\insertframenumber{}/\inserttotalframenumber%
|
||||
\end{beamercolorbox}%
|
||||
\begin{beamercolorbox}[wd=20mm, ht=\kitbottomheight, dp=\kitbottomdepth]{}
|
||||
\usebeamerfont{date in head/foot}%
|
||||
\strut\insertshortdate%
|
||||
\end{beamercolorbox}%
|
||||
% Die Boxen mit dem Titel und dem Gruppennamen sind vertikal zentriert, damit auch zweizeilige Texte schön aussehen
|
||||
% Daher müssen sie um \kitbottomdepth nach unten verschoben werden
|
||||
\raisebox{-\kitbottomdepth}{
|
||||
% Die Box hat daher auch Höhe \kitbottom und Tiefe 0mm
|
||||
\begin{beamercolorbox}[wd=\dimexpr\paperwidth-37mm-\kitfootergroupwidth, ht=\kitbottom, dp=0mm]{}%
|
||||
% Inhalt vertikal zentrieren; Anpassung um 1.5 pt, damit bei einzeiligem Inhalt genau die Baseline der Blöcke mit Seitenzahl und Datum getroffen wird
|
||||
\vbox to\kitbottom{\vfill\vskip1.5pt%
|
||||
\beamer@shortauthor\ifx\beamer@shortauthor\empty\else: \fi\beamer@shorttitle%
|
||||
\vfill}%
|
||||
\end{beamercolorbox}%
|
||||
\ifdefined\@groupname%
|
||||
\begin{beamercolorbox}[wd=\kitfootergroupwidth, ht=\kitbottom, dp=0mm, rightskip=\kitinnermargin]{}
|
||||
\vbox to\kitbottom{\vfill\vskip1.5pt%
|
||||
\raggedleft\@groupname%
|
||||
\vfill}%
|
||||
\end{beamercolorbox}%
|
||||
\fi%
|
||||
}%
|
||||
}
|
||||
|
||||
%% Option "navbarside"
|
||||
\ifnavbarside
|
||||
\useoutertheme[height=0cm,width=3.5cm,left]{sidebar}
|
||||
|
||||
\setbeamerfont{title in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{10pt}{11pt}}}
|
||||
\setbeamerfont{section in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{9pt}{9.9pt}}}
|
||||
\setbeamerfont{subsection in sidebar}{family=\sffamily,series=\mdseries,size={\fontsize{8pt}{8.8pt}}}
|
||||
|
||||
\setbeamertemplate{sidebar \beamer@sidebarside}
|
||||
{\vskip1.5cm%
|
||||
\hskip6.5mm%
|
||||
\advance\beamer@sidebarwidth by -5mm%
|
||||
\insertverticalnavigation{\beamer@sidebarwidth}%
|
||||
}%
|
||||
\fi
|
||||
|
||||
%% Hintergrund
|
||||
\usebackgroundtemplate{
|
||||
% Trennlinie nicht bei "plain"-Frames
|
||||
\ifbeamer@plainframe\else\kitseparationline\fi
|
||||
}
|
||||
|
||||
% Trennlinie
|
||||
\newcommand{\kitseparationline}{
|
||||
\begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\paperheight}
|
||||
\pgfsetstrokecolor{black!15}
|
||||
\pgfsetlinewidth{.5pt}
|
||||
\pgfpathmoveto{\pgfpoint{\kitoutermargin}{\kitinnermargin}}
|
||||
\pgfpathlineto{\pgfpoint{\paperwidth-\kitoutermargin}{\kitinnermargin}}
|
||||
\pgfusepath{stroke}
|
||||
\end{pgfpicture}%
|
||||
}
|
||||
|
||||
|
||||
%% --------------
|
||||
%% | Titelseite |
|
||||
%% --------------
|
||||
|
||||
\def\titleimage#1{\def\@titleimage{#1}}
|
||||
\def\grouplogo#1{\def\@grouplogo{#1}}
|
||||
|
||||
\newcommand{\KITtitleframe}{
|
||||
\begin{frame}[plain]
|
||||
\titlepage
|
||||
\end{frame}
|
||||
}
|
||||
|
||||
\newlength{\kittitleimageheight}
|
||||
\setbeamertemplate{title page}{
|
||||
% From textpos documentation (https://ctan.org/pkg/textpos)
|
||||
%
|
||||
% \begin{textblock}{<hsize>}[<ho>,<vo>](<hpos>,<vpos>)
|
||||
% The coordinates <ho> and <vo> are fractions of the width and height of the text
|
||||
% box, respectively, and state that the box is to be placed so that the reference point
|
||||
% (<ho>,<vo>) within the box is to be placed at the point (<hpos>,<vpos>) on the page.
|
||||
|
||||
% KIT-Logo
|
||||
\begin{textblock*}{30mm}(\kitinnermargin,6.7mm)
|
||||
\includegraphics[width=30mm]{logos/\@kitlogo}
|
||||
\end{textblock*}
|
||||
|
||||
% Gruppenlogo
|
||||
\ifdefined\@grouplogo
|
||||
\ifx\@grouplogo\empty \else
|
||||
\begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm)
|
||||
\includegraphics[width=20mm,height=20mm,keepaspectratio]{logos/\@grouplogo}
|
||||
\end{textblock*}
|
||||
\fi % falls \grouplogo{} aufgerufen wird, kein Gruppenlogo einbinden
|
||||
\else
|
||||
\begin{textblock*}{20mm}(\dimexpr\paperwidth-24mm\relax,6.7mm)
|
||||
\colorbox{kit-purple100!20}{\parbox[t][12mm][c]{19mm}{\color{kit-purple100}\scriptsize\centering
|
||||
\ifgerman
|
||||
Bitte Logo über \texttt{\textbackslash grouplogo\{\}} festlegen.
|
||||
\else
|
||||
Please set a logo using \texttt{\textbackslash grouplogo\{\}}.
|
||||
\fi
|
||||
}}
|
||||
\end{textblock*}
|
||||
\fi
|
||||
|
||||
% Titel
|
||||
\begin{textblock*}{\dimexpr\paperwidth-8mm\relax}[0,.5](\kitinnermargin,28mm)
|
||||
\usebeamerfont*{title}\inserttitle
|
||||
\end{textblock*}
|
||||
|
||||
% Untertitel
|
||||
\begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,36mm)
|
||||
\small\textbf{\insertsubtitle}
|
||||
\end{textblock*}
|
||||
|
||||
% Autor
|
||||
\begin{textblock*}{\dimexpr\paperwidth-8mm\relax}(\kitinnermargin,41mm)
|
||||
\small\insertauthor~\textbar~\insertdate
|
||||
\end{textblock*}
|
||||
|
||||
% Titelbild
|
||||
\setlength{\kittitleimageheight}{40mm}
|
||||
\begin{textblock*}{\paperwidth}(\kitoutermargin,\dimexpr\paperheight-\kitbottommargin-\kittitleimageheight)
|
||||
\begin{pgfpicture}{0mm}{0mm}{\paperwidth}{\kittitleimageheight}
|
||||
% Clipping-Pfad um titelbild
|
||||
\pgfsetstrokecolor{black!15}
|
||||
\pgfsetlinewidth{1pt}
|
||||
\pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
|
||||
\pgfpathmoveto{\pgfpoint{\paperwidth-2\kitoutermargin}{0mm}}
|
||||
\pgfpathlineto{\pgfpoint{\paperwidth-2\kitoutermargin}{\kittitleimageheight}}
|
||||
\pgfsetcornersarced{\pgfpointorigin}
|
||||
\pgfpathlineto{\pgfpoint{0mm}{\kittitleimageheight}}
|
||||
\pgfsetcornersarced{\pgfpoint{3mm}{3mm}}
|
||||
\pgfpathlineto{\pgfpointorigin}
|
||||
\pgfsetcornersarced{\pgfpointorigin}
|
||||
\pgfpathclose
|
||||
\pgfusepath{stroke,clip}
|
||||
\pgfsetstrokecolor{black}
|
||||
|
||||
% Titelbild
|
||||
\ifdefined\@titleimage
|
||||
\ifx\@titleimage\empty \else%
|
||||
\pgftext[at=\pgfpoint{.5\paperwidth}{0mm},center,bottom]{%
|
||||
\includegraphics[height=40mm]{logos/\@titleimage}
|
||||
}
|
||||
\fi % Bei Aufruf von \titleimage{} leeren Rahmen anzeigen.
|
||||
\else
|
||||
\pgftext[at=\pgfpoint{.5\paperwidth}{.5\kittitleimageheight},center,base]{%
|
||||
\colorbox{kit-purple100!20}{\parbox[c][\kittitleimageheight][c]{\paperwidth}{\color{kit-purple100}\centering Bitte Titelbild über \texttt{\textbackslash titleimage\{\}} festlegen.
|
||||
}}%
|
||||
}
|
||||
\fi
|
||||
|
||||
|
||||
\end{pgfpicture}%
|
||||
\end{textblock*}
|
||||
|
||||
|
||||
% KIT slogan
|
||||
\begin{textblock*}{80mm}[0,.5](\kitoutermargin,\dimexpr\paperheight-.5\kitbottommargin)
|
||||
\fontsize{5.5pt}{5.5pt}\selectfont\@kitslogan
|
||||
\end{textblock*}
|
||||
|
||||
\begin{textblock*}{30mm}[1,.5](\dimexpr\paperwidth-\kitoutermargin\relax,\dimexpr\paperheight-.5\kitbottommargin)
|
||||
\fontsize{11pt}{11pt}\selectfont\bfseries\raggedleft%
|
||||
{\href{https://www.kit.edu}{www.kit.edu}}
|
||||
\end{textblock*}
|
||||
|
||||
}
|
||||
%% ---------------
|
||||
%% | /Titelseite |
|
||||
%% ---------------
|
||||
|
||||
%% ----------
|
||||
%% | Farben |
|
||||
%% ----------
|
||||
%% KIT-Farbschema
|
||||
|
||||
% KIT color green :
|
||||
\definecolor{kit-green}{RGB}{0, 150, 130}
|
||||
\definecolor{kit-green100}{RGB}{0, 150, 130}
|
||||
\definecolor{kit-green90}{rgb}{0.1, 0.6294, 0.5588}
|
||||
\definecolor{kit-green80}{rgb}{0.2, 0.6706, 0.6078}
|
||||
\definecolor{kit-green75}{rgb}{0.25, 0.6912, 0.6324}
|
||||
\definecolor{kit-green70}{rgb}{0.3, 0.7118, 0.6569}
|
||||
\definecolor{kit-green60}{rgb}{0.4, 0.7529, 0.7059}
|
||||
\definecolor{kit-green50}{rgb}{0.5, 0.7941, 0.7549}
|
||||
\definecolor{kit-green40}{rgb}{0.6, 0.8353, 0.8039}
|
||||
\definecolor{kit-green30}{rgb}{0.7, 0.8765, 0.8529}
|
||||
\definecolor{kit-green25}{rgb}{0.75, 0.8971, 0.8775}
|
||||
\definecolor{kit-green20}{rgb}{0.8, 0.9176, 0.902}
|
||||
\definecolor{kit-green15}{rgb}{0.85, 0.9382, 0.9265}
|
||||
\definecolor{kit-green10}{rgb}{0.9, 0.9588, 0.951}
|
||||
\definecolor{kit-green5}{rgb}{0.95, 0.9794, 0.9755}
|
||||
|
||||
% KIT color blue:
|
||||
\definecolor{kit-blue}{RGB}{70, 100, 170}
|
||||
\definecolor{kit-blue100}{RGB}{70, 100, 170}
|
||||
\definecolor{kit-blue90}{rgb}{0.3471, 0.4529, 0.7}
|
||||
\definecolor{kit-blue80}{rgb}{0.4196, 0.5137, 0.7333}
|
||||
\definecolor{kit-blue75}{rgb}{0.4559, 0.5441, 0.75}
|
||||
\definecolor{kit-blue70}{rgb}{0.4922, 0.5745, 0.7667}
|
||||
\definecolor{kit-blue60}{rgb}{0.5647, 0.6353, 0.8}
|
||||
\definecolor{kit-blue50}{rgb}{0.6373, 0.6961, 0.8333}
|
||||
\definecolor{kit-blue40}{rgb}{0.7098, 0.7569, 0.8667}
|
||||
\definecolor{kit-blue30}{rgb}{0.7824, 0.8176, 0.9}
|
||||
\definecolor{kit-blue25}{rgb}{0.8186, 0.848, 0.9167}
|
||||
\definecolor{kit-blue20}{rgb}{0.8549, 0.8784, 0.9333}
|
||||
\definecolor{kit-blue15}{rgb}{0.8912, 0.9088, 0.95}
|
||||
\definecolor{kit-blue10}{rgb}{0.9275, 0.9392, 0.9667}
|
||||
\definecolor{kit-blue5}{rgb}{0.9637, 0.9696, 0.9833}
|
||||
|
||||
% KIT color red :
|
||||
\definecolor{kit-red}{RGB}{162, 34, 35}
|
||||
\definecolor{kit-red100}{RGB}{162, 34, 35}
|
||||
\definecolor{kit-red90}{rgb}{0.6718, 0.22, 0.2235}
|
||||
\definecolor{kit-red80}{rgb}{0.7082, 0.3067, 0.3098}
|
||||
\definecolor{kit-red75}{rgb}{0.7265, 0.35, 0.3529}
|
||||
\definecolor{kit-red70}{rgb}{0.7447, 0.3933, 0.3961}
|
||||
\definecolor{kit-red60}{rgb}{0.7812, 0.48, 0.4824}
|
||||
\definecolor{kit-red50}{rgb}{0.8176, 0.5667, 0.5686}
|
||||
\definecolor{kit-red40}{rgb}{0.8541, 0.6533, 0.6549}
|
||||
\definecolor{kit-red30}{rgb}{0.8906, 0.74, 0.7412}
|
||||
\definecolor{kit-red25}{rgb}{0.9088, 0.7833, 0.7843}
|
||||
\definecolor{kit-red20}{rgb}{0.9271, 0.8267, 0.8275}
|
||||
\definecolor{kit-red15}{rgb}{0.9453, 0.87, 0.8706}
|
||||
\definecolor{kit-red10}{rgb}{0.9635, 0.9133, 0.9137}
|
||||
\definecolor{kit-red5}{rgb}{0.9818, 0.9567, 0.9569}
|
||||
|
||||
% KIT color yellow :
|
||||
\definecolor{kit-yellow}{RGB}{252, 229, 0}
|
||||
\definecolor{kit-yellow100}{RGB}{252, 229, 0}
|
||||
\definecolor{kit-yellow90}{rgb}{0.9894, 0.9082, 0.1}
|
||||
\definecolor{kit-yellow80}{rgb}{0.9906, 0.9184, 0.2}
|
||||
\definecolor{kit-yellow75}{rgb}{0.9912, 0.9235, 0.25}
|
||||
\definecolor{kit-yellow70}{rgb}{0.9918, 0.9286, 0.3}
|
||||
\definecolor{kit-yellow60}{rgb}{0.9929, 0.9388, 0.4}
|
||||
\definecolor{kit-yellow50}{rgb}{0.9941, 0.949, 0.5}
|
||||
\definecolor{kit-yellow40}{rgb}{0.9953, 0.9592, 0.6}
|
||||
\definecolor{kit-yellow30}{rgb}{0.9965, 0.9694, 0.7}
|
||||
\definecolor{kit-yellow25}{rgb}{0.9971, 0.9745, 0.75}
|
||||
\definecolor{kit-yellow20}{rgb}{0.9976, 0.9796, 0.8}
|
||||
\definecolor{kit-yellow15}{rgb}{0.9982, 0.9847, 0.85}
|
||||
\definecolor{kit-yellow10}{rgb}{0.9988, 0.9898, 0.9}
|
||||
\definecolor{kit-yellow5}{rgb}{0.9994, 0.9949, 0.95}
|
||||
|
||||
% KIT color orange :
|
||||
\definecolor{kit-orange}{RGB}{223, 155, 27}
|
||||
\definecolor{kit-orange100}{RGB}{223, 155, 27}
|
||||
\definecolor{kit-orange90}{rgb}{0.8871, 0.6471, 0.1953}
|
||||
\definecolor{kit-orange80}{rgb}{0.8996, 0.6863, 0.2847}
|
||||
\definecolor{kit-orange75}{rgb}{0.9059, 0.7059, 0.3294}
|
||||
\definecolor{kit-orange70}{rgb}{0.9122, 0.7255, 0.3741}
|
||||
\definecolor{kit-orange60}{rgb}{0.9247, 0.7647, 0.4635}
|
||||
\definecolor{kit-orange50}{rgb}{0.9373, 0.8039, 0.5529}
|
||||
\definecolor{kit-orange40}{rgb}{0.9498, 0.8431, 0.6424}
|
||||
\definecolor{kit-orange30}{rgb}{0.9624, 0.8824, 0.7318}
|
||||
\definecolor{kit-orange25}{rgb}{0.9686, 0.902, 0.7765}
|
||||
\definecolor{kit-orange20}{rgb}{0.9749, 0.9216, 0.8212}
|
||||
\definecolor{kit-orange15}{rgb}{0.9812, 0.9412, 0.8659}
|
||||
\definecolor{kit-orange10}{rgb}{0.9875, 0.9608, 0.9106}
|
||||
\definecolor{kit-orange5}{rgb}{0.9937, 0.9804, 0.9553}
|
||||
|
||||
% KIT color lightgreen :
|
||||
\definecolor{kit-lightgreen}{RGB}{140, 182, 60}
|
||||
\definecolor{kit-lightgreen100}{RGB}{140, 182, 60}
|
||||
\definecolor{kit-lightgreen90}{rgb}{0.5941, 0.7424, 0.3118}
|
||||
\definecolor{kit-lightgreen80}{rgb}{0.6392, 0.771, 0.3882}
|
||||
\definecolor{kit-lightgreen75}{rgb}{0.6618, 0.7853, 0.4265}
|
||||
\definecolor{kit-lightgreen70}{rgb}{0.6843, 0.7996, 0.4647}
|
||||
\definecolor{kit-lightgreen60}{rgb}{0.7294, 0.8282, 0.5412}
|
||||
\definecolor{kit-lightgreen50}{rgb}{0.7745, 0.8569, 0.6176}
|
||||
\definecolor{kit-lightgreen40}{rgb}{0.8196, 0.8855, 0.6941}
|
||||
\definecolor{kit-lightgreen30}{rgb}{0.8647, 0.9141, 0.7706}
|
||||
\definecolor{kit-lightgreen25}{rgb}{0.8873, 0.9284, 0.8088}
|
||||
\definecolor{kit-lightgreen20}{rgb}{0.9098, 0.9427, 0.8471}
|
||||
\definecolor{kit-lightgreen15}{rgb}{0.9324, 0.9571, 0.8853}
|
||||
\definecolor{kit-lightgreen10}{rgb}{0.9549, 0.9714, 0.9235}
|
||||
\definecolor{kit-lightgreen5}{rgb}{0.9775, 0.9857, 0.9618}
|
||||
|
||||
|
||||
% KIT color purple :
|
||||
\definecolor{kit-purple}{RGB}{163, 16, 124}
|
||||
\definecolor{kit-purple100}{RGB}{163, 16, 124}
|
||||
\definecolor{kit-purple90}{rgb}{0.6753, 0.1565, 0.5376}
|
||||
\definecolor{kit-purple80}{rgb}{0.7114, 0.2502, 0.589}
|
||||
\definecolor{kit-purple75}{rgb}{0.7294, 0.2971, 0.6147}
|
||||
\definecolor{kit-purple70}{rgb}{0.7475, 0.3439, 0.6404}
|
||||
\definecolor{kit-purple60}{rgb}{0.7835, 0.4376, 0.6918}
|
||||
\definecolor{kit-purple50}{rgb}{0.8196, 0.5314, 0.7431}
|
||||
\definecolor{kit-purple40}{rgb}{0.8557, 0.6251, 0.7945}
|
||||
\definecolor{kit-purple30}{rgb}{0.8918, 0.7188, 0.8459}
|
||||
\definecolor{kit-purple25}{rgb}{0.9098, 0.7657, 0.8716}
|
||||
\definecolor{kit-purple20}{rgb}{0.9278, 0.8125, 0.8973}
|
||||
\definecolor{kit-purple15}{rgb}{0.9459, 0.8594, 0.9229}
|
||||
\definecolor{kit-purple10}{rgb}{0.9639, 0.9063, 0.9486}
|
||||
\definecolor{kit-purple5}{rgb}{0.982, 0.9531, 0.9743}
|
||||
|
||||
% KIT color brown :
|
||||
\definecolor{kit-brown}{RGB}{167, 130, 46}
|
||||
\definecolor{kit-brown100}{RGB}{167, 130, 46}
|
||||
\definecolor{kit-brown90}{rgb}{0.6894, 0.5588, 0.2624}
|
||||
\definecolor{kit-brown80}{rgb}{0.7239, 0.6078, 0.3443}
|
||||
\definecolor{kit-brown75}{rgb}{0.7412, 0.6324, 0.3853}
|
||||
\definecolor{kit-brown70}{rgb}{0.7584, 0.6569, 0.4263}
|
||||
\definecolor{kit-brown60}{rgb}{0.7929, 0.7059, 0.5082}
|
||||
\definecolor{kit-brown50}{rgb}{0.8275, 0.7549, 0.5902}
|
||||
\definecolor{kit-brown40}{rgb}{0.862, 0.8039, 0.6722}
|
||||
\definecolor{kit-brown30}{rgb}{0.8965, 0.8529, 0.7541}
|
||||
\definecolor{kit-brown25}{rgb}{0.9137, 0.8775, 0.7951}
|
||||
\definecolor{kit-brown20}{rgb}{0.931, 0.902, 0.8361}
|
||||
\definecolor{kit-brown15}{rgb}{0.9482, 0.9265, 0.8771}
|
||||
\definecolor{kit-brown10}{rgb}{0.9655, 0.951, 0.918}
|
||||
\definecolor{kit-brown5}{rgb}{0.9827, 0.9755, 0.959}
|
||||
|
||||
% KIT color cyan :
|
||||
\definecolor{kit-cyan}{RGB}{35, 161, 224}
|
||||
\definecolor{kit-cyan100}{RGB}{35, 161, 224}
|
||||
\definecolor{kit-cyan90}{rgb}{0.2235, 0.6682, 0.8906}
|
||||
\definecolor{kit-cyan80}{rgb}{0.3098, 0.7051, 0.9027}
|
||||
\definecolor{kit-cyan75}{rgb}{0.3529, 0.7235, 0.9088}
|
||||
\definecolor{kit-cyan70}{rgb}{0.3961, 0.742, 0.9149}
|
||||
\definecolor{kit-cyan60}{rgb}{0.4824, 0.7788, 0.9271}
|
||||
\definecolor{kit-cyan50}{rgb}{0.5686, 0.8157, 0.9392}
|
||||
\definecolor{kit-cyan40}{rgb}{0.6549, 0.8525, 0.9514}
|
||||
\definecolor{kit-cyan30}{rgb}{0.7412, 0.8894, 0.9635}
|
||||
\definecolor{kit-cyan25}{rgb}{0.7843, 0.9078, 0.9696}
|
||||
\definecolor{kit-cyan20}{rgb}{0.8275, 0.9263, 0.9757}
|
||||
\definecolor{kit-cyan15}{rgb}{0.8706, 0.9447, 0.9818}
|
||||
\definecolor{kit-cyan10}{rgb}{0.9137, 0.9631, 0.9878}
|
||||
\definecolor{kit-cyan5}{rgb}{0.9569, 0.9816, 0.9939}
|
||||
|
||||
% KIT color gray :
|
||||
\definecolor{kit-gray}{RGB}{0, 0, 0}
|
||||
\definecolor{kit-gray100}{RGB}{0, 0, 0}
|
||||
\definecolor{kit-gray90}{rgb}{0.1, 0.1, 0.1}
|
||||
\definecolor{kit-gray80}{rgb}{0.2, 0.2, 0.2}
|
||||
\definecolor{kit-gray75}{rgb}{0.25, 0.25, 0.25}
|
||||
\definecolor{kit-gray70}{rgb}{0.3, 0.3, 0.3}
|
||||
\definecolor{kit-gray60}{rgb}{0.4, 0.4, 0.4}
|
||||
\definecolor{kit-gray50}{rgb}{0.5, 0.5, 0.5}
|
||||
\definecolor{kit-gray40}{rgb}{0.6, 0.6, 0.6}
|
||||
\definecolor{kit-gray30}{rgb}{0.7, 0.7, 0.7}
|
||||
\definecolor{kit-gray25}{rgb}{0.75, 0.75, 0.75}
|
||||
\definecolor{kit-gray20}{rgb}{0.8, 0.8, 0.8}
|
||||
\definecolor{kit-gray15}{rgb}{0.85, 0.85, 0.85}
|
||||
\definecolor{kit-gray10}{rgb}{0.9, 0.9, 0.9}
|
||||
\definecolor{kit-gray5}{rgb}{0.95, 0.95, 0.95}
|
||||
|
||||
|
||||
|
||||
\setbeamercolor*{normal text}{fg=black}
|
||||
\setbeamercolor*{alerted text}{fg=kit-red100}
|
||||
\setbeamercolor*{example text}{fg=black}
|
||||
\setbeamercolor*{structure}{fg=black}
|
||||
|
||||
\setbeamercolor*{palette primary}{fg=black,bg=black!15}
|
||||
\setbeamercolor*{palette secondary}{fg=black,bg=black!15}
|
||||
\setbeamercolor*{palette tertiary}{fg=black,bg=black!15}
|
||||
\setbeamercolor*{palette quaternary}{fg=black,bg=black!15}
|
||||
|
||||
\setbeamercolor*{palette sidebar primary}{fg=black!75}
|
||||
\setbeamercolor*{palette sidebar secondary}{fg=black!75}
|
||||
\setbeamercolor*{palette sidebar tertiary}{fg=black!75}
|
||||
\setbeamercolor*{palette sidebar quaternary}{fg=black!75}
|
||||
|
||||
\setbeamercolor*{item projected}{fg=white,bg=kit-green100}
|
||||
|
||||
\setbeamercolor*{block title}{fg=white,bg=kit-green100}
|
||||
\setbeamercolor*{block title alerted}{use=alerted text,fg=white,bg=alerted text.fg!75!black}
|
||||
\setbeamercolor*{block title example}{fg=white,bg=kit-blue100}
|
||||
|
||||
\setbeamercolor*{block body}{fg=black,bg=kit-green15}
|
||||
\setbeamercolor*{block body alerted}{parent=normal text,use=block title alerted,bg=block title alerted.bg!10!bg}
|
||||
\setbeamercolor*{block body example}{fg=black,bg=kit-blue15}
|
||||
|
||||
\setbeamercolor*{separation line}{}
|
||||
\setbeamercolor*{fine separation line}{}
|
||||
|
||||
\setbeamercolor*{background canvas}{bg=white}
|
||||
|
||||
%% -----------
|
||||
%% | /Farben |
|
||||
%% -----------
|
||||
|
||||
%% -----------------------------------
|
||||
%% | halbgerundete Aufzählungspunkte |
|
||||
%% -----------------------------------
|
||||
|
||||
% KIT-Aufzählungszeichen
|
||||
\newcommand{\KITmark}{%
|
||||
\begin{pgfpicture}{0mm}{0mm}{1ex}{1ex}
|
||||
{\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}}
|
||||
\pgfpathmoveto{\pgfpoint{0cm}{1ex}}
|
||||
\pgfpathlineto{\pgfpoint{1ex}{1ex}}
|
||||
\pgfpathlineto{\pgfpoint{1ex}{0cm}}}
|
||||
{\pgfsetcornersarced{\pgfpoint{.3ex}{.3ex}}
|
||||
\pgfpathmoveto{\pgfpoint{1ex}{0cm}}
|
||||
\pgfpathlineto{\pgfpointorigin}
|
||||
\pgfpathlineto{\pgfpoint{0cm}{1ex}}}
|
||||
\color{kit-green100}
|
||||
\pgfusepath{fill}
|
||||
\end{pgfpicture}%
|
||||
}
|
||||
|
||||
\setbeamertemplate{itemize items}{\raisebox{.2ex}{\KITmark}}
|
||||
|
||||
%% ----------------------
|
||||
%% | Inhaltsverzeichnis |
|
||||
%% ----------------------
|
||||
|
||||
\setbeamertemplate{section in toc}{\normalsize\textbf{\textcolor{kit-blue}{\inserttocsectionnumber.~\inserttocsection}}\par}
|
||||
\setbeamertemplate{subsection in toc}{\small\hspace{1.2em}\raisebox{.2ex}{\KITmark}\hspace{\labelsep}\inserttocsubsection\par}
|
||||
|
||||
%% ------------------------------
|
||||
%% | halbgerundete Beamer-Boxen |
|
||||
%% ------------------------------
|
||||
|
||||
\renewcommand\beamerboxesrounded[2][]{%
|
||||
\global\let\beamer@firstlineitemizeunskip=\relax%
|
||||
\vbox\bgroup%
|
||||
\setkeys{beamerboxes}{upper=block title,lower=block body,width=\textwidth,shadow=false}%
|
||||
\setkeys{beamerboxes}{#1}%
|
||||
{%
|
||||
\usebeamercolor{\bmb@lower}%
|
||||
\globalcolorstrue%
|
||||
\colorlet{lower.bg}{bg}%
|
||||
}%
|
||||
{%
|
||||
\usebeamercolor{\bmb@upper}%
|
||||
\globalcolorstrue%
|
||||
\colorlet{upper.bg}{bg}%
|
||||
}%
|
||||
%
|
||||
% Typeset head
|
||||
%
|
||||
\vskip4bp
|
||||
\setbox\bmb@box=\hbox{%
|
||||
\begin{minipage}[b]{\bmb@width}%
|
||||
\usebeamercolor[fg]{\bmb@upper}%
|
||||
#2%
|
||||
\end{minipage}}%
|
||||
\ifdim\wd\bmb@box=0pt%
|
||||
\setbox\bmb@box=\hbox{}%
|
||||
\ht\bmb@box=1.5pt%
|
||||
\bmb@prevheight=-4.5pt%
|
||||
\else%
|
||||
\wd\bmb@box=\bmb@width%
|
||||
\bmb@temp=\dp\bmb@box%
|
||||
\ifdim\bmb@temp<1.5pt%
|
||||
\bmb@temp=1.5pt%
|
||||
\fi%
|
||||
\setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
|
||||
\dp\bmb@box=0pt%
|
||||
\bmb@prevheight=\ht\bmb@box%
|
||||
\fi%
|
||||
\bmb@temp=\bmb@width%
|
||||
\bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp%
|
||||
\bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
|
||||
\hbox{%
|
||||
\begin{pgfpicture}{0bp}{+-\ht\bmb@box}{0bp}{+-\ht\bmb@box}
|
||||
\ifdim\wd\bmb@box=0pt%
|
||||
\color{lower.bg}%
|
||||
\else%
|
||||
\color{upper.bg}%
|
||||
\fi%
|
||||
\pgfpathqmoveto{-4bp}{-1bp}
|
||||
% Adaption for "KIT-Design"
|
||||
\pgfpathlineto{\pgfpoint{-4bp}{3bp}}
|
||||
%\pgfpathqcurveto{-4bp}{1.2bp}{-2.2bp}{3bp}{0bp}{3bp}
|
||||
\pgfpathlineto{\pgfpoint{\bmb@temp}{3bp}}
|
||||
\pgfpathcurveto%
|
||||
{\pgfpoint{\bmb@dima}{3bp}}%
|
||||
{\pgfpoint{\bmb@dimb}{1.2bp}}%
|
||||
{\pgfpoint{\bmb@dimb}{-1bp}}%
|
||||
\bmb@dima=-\ht\bmb@box%
|
||||
\advance\bmb@dima by-2pt%
|
||||
\pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
|
||||
\pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}}
|
||||
\pgfusepath{fill}
|
||||
\end{pgfpicture}%
|
||||
\copy\bmb@box%
|
||||
}%
|
||||
\nointerlineskip%
|
||||
\vskip-1pt%
|
||||
\ifdim\wd\bmb@box=0pt%
|
||||
\else%
|
||||
\hbox{%
|
||||
\begin{pgfpicture}{0pt}{0pt}{\bmb@width}{6pt}
|
||||
\bmb@dima=\bmb@width%
|
||||
\advance\bmb@dima by8bp%
|
||||
\pgfpathrectangle{\pgfpoint{-4bp}{-1bp}}{\pgfpoint{\bmb@dima}{8bp}}
|
||||
\pgfusepath{clip}
|
||||
{\pgftransformshift{\pgfpoint{-4bp}{0bp}}\pgftext[left,base]{\pgfuseshading{bmb@transition}}}%
|
||||
\end{pgfpicture}%
|
||||
}%
|
||||
\nointerlineskip%
|
||||
\vskip-0.5pt%
|
||||
\fi%
|
||||
\ifbmb@shadow%
|
||||
\setbox\bmb@boxshadow=\hbox{\pgfuseshading{bmb@shadow}}%
|
||||
\setbox\bmb@boxshadowball=\hbox{\pgfuseshading{bmb@shadowball}}%
|
||||
\setbox\bmb@boxshadowballlarge=\hbox{\pgfuseshading{bmb@shadowballlarge}}%
|
||||
\fi%
|
||||
\setbox\bmb@colorbox=\hbox{{\pgfpicturetrue\pgfsetcolor{lower.bg}}}%
|
||||
\setbox\bmb@box=\hbox\bgroup\begin{minipage}[b]{\bmb@width}%
|
||||
\vskip2pt%
|
||||
\usebeamercolor[fg]{\bmb@lower}%
|
||||
\colorlet{beamerstructure}{upper.bg}%
|
||||
\colorlet{structure}{upper.bg}%
|
||||
%\color{.}%
|
||||
}
|
||||
|
||||
\def\endbeamerboxesrounded{%
|
||||
\end{minipage}\egroup%
|
||||
\wd\bmb@box=\bmb@width%
|
||||
\bmb@temp=\dp\bmb@box%
|
||||
\advance\bmb@temp by.5pt%
|
||||
\setbox\bmb@box=\hbox{\raise\bmb@temp\hbox{\box\bmb@box}}%
|
||||
\dp\bmb@box=0pt%
|
||||
\bmb@temp=\wd\bmb@box%
|
||||
\bmb@dima=\bmb@temp\advance\bmb@dima by2.2bp%
|
||||
\bmb@dimb=\bmb@temp\advance\bmb@dimb by4bp%
|
||||
\hbox{%
|
||||
\begin{pgfpicture}{0bp}{0bp}{0bp}{0bp}
|
||||
\ifbmb@shadow%
|
||||
{\pgftransformshift{\pgfpoint{4bp}{-3bp}}\pgftext{\copy\bmb@boxshadowball}}
|
||||
\begin{pgfscope}
|
||||
{%
|
||||
\advance\bmb@temp by-1bp%
|
||||
\pgfpathrectangle{\pgfpoint{\bmb@temp}{-7bp}}{\pgfpoint{9bp}{9bp}}%
|
||||
\pgfusepath{clip}
|
||||
}%
|
||||
{\pgftransformshift{\pgfpoint{\bmb@temp}{1bp}}\pgftext{\box\bmb@boxshadowballlarge}}
|
||||
\end{pgfscope}
|
||||
\begin{pgfscope}
|
||||
\advance\bmb@temp by-4bp%
|
||||
\pgfpathrectangle{\pgfpoint{4bp}{-7bp}}{\pgfpoint{\bmb@temp}{5bp}}
|
||||
\pgfusepath{clip}
|
||||
{\pgftransformshift{\pgfpoint{4bp}{-7bp}}\pgftext[left,base]{\copy\bmb@boxshadow}}%
|
||||
\end{pgfscope}
|
||||
\begin{pgfscope}
|
||||
\advance\bmb@temp by 4bp%
|
||||
\bmb@dima=\ht\bmb@box%
|
||||
\advance\bmb@dima by\bmb@prevheight%
|
||||
\advance\bmb@dima by 4bp%
|
||||
\pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}}
|
||||
\pgfusepath{clip}
|
||||
\advance\bmb@dima by-4bp%
|
||||
{\pgftransformshift{\pgfpoint{\bmb@temp}{\bmb@dima}}\pgftext{\box\bmb@boxshadowball}}
|
||||
\advance\bmb@dima by-1bp%
|
||||
\pgfpathrectangle{\pgfpoint{\bmb@temp}{1bp}}{\pgfpoint{4bp}{\bmb@dima}}
|
||||
\pgfusepath{clip}
|
||||
\advance\bmb@temp by4bp%
|
||||
{\pgftransformshift{\pgfpoint{\bmb@temp}{-3bp}}%
|
||||
\pgftransformrotate{90}%
|
||||
\pgftext[left,base]{\box\bmb@boxshadow}}%
|
||||
\end{pgfscope}
|
||||
\fi%
|
||||
\unhbox\bmb@colorbox%
|
||||
\pgfpathqmoveto{-4bp}{1bp}
|
||||
\pgfpathqcurveto{-4bp}{-1.2bp}{-2.2bp}{-3bp}{0bp}{-3bp}
|
||||
\pgfpathlineto{\pgfpoint{\the\bmb@dimb}{-3bp}}
|
||||
{
|
||||
\bmb@dima=\ht\bmb@box%
|
||||
\pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
|
||||
\pgfpathlineto{\pgfpoint{-4bp}{\bmb@dima}}
|
||||
\pgfusepath{fill}
|
||||
}
|
||||
\ifbmb@shadow%
|
||||
{
|
||||
\color{black!50!bg}
|
||||
\pgfsetlinewidth{0pt}
|
||||
\pgfpathmoveto{\pgfpoint{\bmb@dimb}{-.5bp}}
|
||||
\bmb@dima=\ht\bmb@box%
|
||||
\advance\bmb@dima by\bmb@prevheight%
|
||||
\advance\bmb@dima by 1bp%
|
||||
\pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
|
||||
\pgfusepath{stroke}
|
||||
\bmb@temp=\bmb@dima
|
||||
\advance\bmb@dima by 1bp%
|
||||
\color{black!31!bg}
|
||||
\pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
|
||||
\pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
|
||||
\pgfusepath{stroke}
|
||||
\advance\bmb@dima by 1bp%
|
||||
\advance\bmb@temp by 1bp%
|
||||
\color{black!19!bg}
|
||||
\pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
|
||||
\pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
|
||||
\pgfusepath{stroke}
|
||||
\advance\bmb@dima by 1bp%
|
||||
\advance\bmb@temp by 1bp%
|
||||
\color{black!6!bg}
|
||||
\pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
|
||||
\pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
|
||||
\pgfusepath{stroke}
|
||||
\advance\bmb@dima by 1.5bp%
|
||||
\advance\bmb@temp by 1bp%
|
||||
\color{bg}
|
||||
\pgfpathmoveto{\pgfpoint{\bmb@dimb}{\bmb@temp}}
|
||||
\pgfpathlineto{\pgfpoint{\bmb@dimb}{\bmb@dima}}
|
||||
\pgfusepath{stroke}
|
||||
}
|
||||
\fi
|
||||
\end{pgfpicture}%
|
||||
\box\bmb@box%
|
||||
}%
|
||||
\ifbmb@shadow%
|
||||
\vskip4bp minus 2bp%
|
||||
\else%
|
||||
\vskip2bp%
|
||||
\fi%
|
||||
\egroup% of \vbox\bgroup
|
||||
}
|
||||
|
||||
|
||||
%% -------------------------------
|
||||
%% | /halbgerundete Beamer-Boxen |
|
||||
%% -------------------------------
|
||||
|
||||
|
||||
%% ----------------------
|
||||
%% | Block-Definitionen |
|
||||
%% ----------------------
|
||||
|
||||
% Content environment for structuring. Basically a headline followed by text
|
||||
\newenvironment<>{contentblock}[1]{\begingroup%
|
||||
\setbeamertemplate{blocks}[default]
|
||||
\setbeamercolor{block body}{fg=black,bg=}%
|
||||
\setbeamercolor{block title}{fg=black,bg=}%
|
||||
\setbeamerfont*{block title}{family=\sffamily,series=\bfseries,size=\large}
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}%
|
||||
\endgroup}
|
||||
|
||||
|
||||
\newenvironment<>{greenblock}[1]{\begingroup%
|
||||
\setbeamercolor{block body}{fg=black,bg=kit-green15}%
|
||||
\setbeamercolor{block title}{fg=white,bg=kit-green100}%
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}
|
||||
\endgroup}
|
||||
|
||||
\newenvironment<>{blueblock}[1]{\begingroup%
|
||||
\setbeamercolor{block body}{fg=black,bg=kit-blue15}%
|
||||
\setbeamercolor{block title}{fg=white,bg=kit-blue100}%
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}
|
||||
\endgroup}
|
||||
|
||||
\newenvironment<>{redblock}[1]{\begingroup%
|
||||
\setbeamercolor{block body}{fg=black,bg=kit-red15}%
|
||||
\setbeamercolor{block title}{fg=white,bg=kit-red100}%
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}%
|
||||
\endgroup}
|
||||
|
||||
\newenvironment<>{brownblock}[1]{\begingroup%
|
||||
\setbeamercolor{block body}{fg=black,bg=kit-brown15}%
|
||||
\setbeamercolor{block title}{fg=white,bg=kit-brown100}%
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}%
|
||||
\endgroup}
|
||||
|
||||
\newenvironment<>{purpleblock}[1]{\begingroup%
|
||||
\setbeamercolor{block body}{fg=black,bg=kit-purple15}%
|
||||
\setbeamercolor{block title}{fg=white,bg=kit-purple100}%
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}%
|
||||
\endgroup}
|
||||
|
||||
\newenvironment<>{grayblock}[1]{\begingroup%
|
||||
\setbeamercolor{block body}{fg=black,bg=kit-gray15}%
|
||||
\setbeamercolor{block title}{fg=white,bg=kit-gray70}%
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}%
|
||||
\endgroup}
|
||||
|
||||
\newenvironment<>{yellowblock}[1]{\begingroup%
|
||||
\setbeamercolor{block body}{fg=black,bg=kit-yellow30}%
|
||||
\setbeamercolor{block title}{fg=black,bg=kit-yellow100}%
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}%
|
||||
\endgroup}
|
||||
|
||||
\newenvironment<>{lightgreenblock}[1]{\begingroup%
|
||||
\setbeamercolor{block body}{fg=black,bg=kit-lightgreen15}%
|
||||
\setbeamercolor{block title}{fg=white,bg=kit-lightgreen100}%
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}%
|
||||
\endgroup}
|
||||
|
||||
\newenvironment<>{orangeblock}[1]{\begingroup%
|
||||
\setbeamercolor{block body}{fg=black,bg=kit-orange15}%
|
||||
\setbeamercolor{block title}{fg=white,bg=kit-orange100}%
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}%
|
||||
\endgroup}
|
||||
|
||||
\newenvironment<>{cyanblock}[1]{\begingroup%
|
||||
\setbeamercolor{block body}{fg=black,bg=kit-cyan15}%
|
||||
\setbeamercolor{block title}{fg=white,bg=kit-cyan100}%
|
||||
\begin{block}#2{#1}%
|
||||
}{\end{block}%
|
||||
\endgroup}
|
||||
%% ------------------------------
|
||||
%% | /Block-Definitionen |
|
||||
%% ------------------------------
|
||||
|
||||
%% use this for setting the total page number
|
||||
\newcommand{\beginbackup}{
|
||||
\newcounter{framenumbervorappendix}
|
||||
\setcounter{framenumbervorappendix}{\value{framenumber}}
|
||||
}
|
||||
\newcommand{\backupend}{
|
||||
\addtocounter{framenumbervorappendix}{-\value{framenumber}}
|
||||
\addtocounter{framenumber}{\value{framenumbervorappendix}}
|
||||
}
|
40
01-pflichtenheft-kolloquium/slides/einführung.tex
Normal file
|
@ -0,0 +1,40 @@
|
|||
\begin{frame}[t]{Einführung}
|
||||
|
||||
|
||||
\begin{columns}[t]
|
||||
\begin{column}{.3\textwidth}
|
||||
\centering{\fontsize{30pt}{36pt}\selectfont\faPodcast}
|
||||
\vspace{.2cm}
|
||||
\begin{block}{Podcast}
|
||||
\begin{itemize}
|
||||
\item RSS-Feed
|
||||
\item Episoden
|
||||
\item Audio/Video
|
||||
\end{itemize}
|
||||
\end{block}
|
||||
\end{column}
|
||||
\begin{column}{.3\textwidth}
|
||||
\centering{\fontsize{30pt}{36pt}\selectfont\faArrowCircleDown}
|
||||
\vspace{.2cm}
|
||||
\begin{block}{Podcatcher}
|
||||
\begin{itemize}
|
||||
\item lokale Verwaltung von Podcasts
|
||||
\item API Unterstützung
|
||||
\item Abspielen von Episoden
|
||||
\end{itemize}
|
||||
\end{block}
|
||||
\end{column}
|
||||
\begin{column}{.3\textwidth}
|
||||
\centering{\fontsize{30pt}{36pt}\selectfont\faSync}
|
||||
\vspace{.2cm}
|
||||
\begin{block}{Synchronisationsserver}
|
||||
\begin{itemize}
|
||||
\item Hörfortschritte
|
||||
\item Abonnements
|
||||
\item Discovery
|
||||
\end{itemize}
|
||||
\end{block}
|
||||
\end{column}
|
||||
\end{columns}
|
||||
|
||||
\end{frame}
|
37
01-pflichtenheft-kolloquium/slides/features.tex
Normal file
|
@ -0,0 +1,37 @@
|
|||
\begin{frame}{Features}
|
||||
\begin{columns}[t]
|
||||
\begin{column}{.3\textwidth}
|
||||
\centering{\fontsize{30pt}{36pt}\selectfont\faSync}
|
||||
\vspace{.2cm}
|
||||
\begin{block}{Synchronisation}
|
||||
\begin{itemize}
|
||||
\item Abos
|
||||
\item Hörfortschritt
|
||||
\end{itemize}
|
||||
\end{block}
|
||||
\end{column}
|
||||
\begin{column}{.3\textwidth}
|
||||
\centering{\fontsize{30pt}{36pt}\selectfont\faGlobe}
|
||||
\vspace{.2cm}
|
||||
\begin{block}{Weboberfläche}
|
||||
\begin{itemize}
|
||||
\item Aboliste
|
||||
\item Zuletzt gehört
|
||||
\end{itemize}
|
||||
\end{block}
|
||||
\end{column}
|
||||
\begin{column}{.3\textwidth}
|
||||
\centering{\fontsize{30pt}{36pt}\selectfont\faUser}
|
||||
\vspace{.2cm}
|
||||
\begin{block}{Account-Verwaltung}
|
||||
\begin{itemize}
|
||||
\item Registrieren und Anmelden
|
||||
\item Passwort ändern und zurücksetzen
|
||||
\item Account löschen
|
||||
\item Daten importieren/exportieren
|
||||
\end{itemize}
|
||||
\end{block}
|
||||
\end{column}
|
||||
\end{columns}
|
||||
\end{frame}
|
||||
|
36
01-pflichtenheft-kolloquium/slides/synchronisation.tex
Normal file
|
@ -0,0 +1,36 @@
|
|||
\begin{frame}{Synchronisation}
|
||||
|
||||
\tikzstyle{line} = [draw, -latex']
|
||||
|
||||
\begin{figure}[H]
|
||||
|
||||
\begin{tikzpicture}
|
||||
|
||||
\tikzset{focus/.style={rectangle, minimum width = 1cm, minimum height = 0.5cm, rounded corners, draw}};
|
||||
\tikzset{hyperfocus/.style={rectangle, minimum width = 1cm, minimum height = 0.5cm, draw}};
|
||||
|
||||
\node[hyperfocus, text width = 2.6cm, fill = green!25](s){Synchronisations-\\\quad \quad Server};
|
||||
\node[focus, left = 3cm of s, text width = 3.1cm, orange](p1){\quad \underline{p1:Podcatcher}
|
||||
\begin{itemize}
|
||||
\vspace{0.2cm}
|
||||
\item Abonnements
|
||||
\item Hörfortschritt
|
||||
\vspace{0.1cm}
|
||||
\end{itemize}};
|
||||
\node[focus, above = 1.8cm of s, orange](p2){p2};
|
||||
\node[focus, right = 2.5cm of s, orange](p3){p3};
|
||||
\node[below = 1.7cm of s](p4){\textbf{...}};
|
||||
\umlactor[left = 2.7cm of p2, blue!60]{Benutzer};
|
||||
|
||||
\draw[] (p1) -- (s);
|
||||
\draw[] (p2) -- (s);
|
||||
\draw[] (s) -- (p3);
|
||||
\draw[] (s) -- (p4);
|
||||
\path [line, thick, blue!60] (Benutzer) -- node [text width=2.5cm, midway, above=0.1cm, align=center] {Podcast abonnieren} (p2);
|
||||
\path [line, thick, blue!60] (Benutzer) -| node [text width=2.5cm, midway, above=0.1cm, align=center] {Episode anhören} (p1);
|
||||
|
||||
\end{tikzpicture}
|
||||
|
||||
\end{figure}
|
||||
|
||||
\end{frame}
|
39
01-pflichtenheft-kolloquium/slides/zielsetzung.tex
Normal file
|
@ -0,0 +1,39 @@
|
|||
\begin{frame}{Zielsetzung}
|
||||
|
||||
\begin{figure}[H]
|
||||
|
||||
\raggedright
|
||||
|
||||
\begin{tikzpicture}
|
||||
|
||||
\tikzset{focus/.style={rectangle, minimum width=1cm, minimum height=0.5cm, rounded corners=7pt, draw}};
|
||||
|
||||
\tikzset{hyperfocus/.style={rectangle, minimum width=1cm, minimum height=0.5cm, draw}};
|
||||
|
||||
\node[hyperfocus] (main) {gPodder};
|
||||
\node[focus, right = 2cm of main] (sync) {Synchronisation};
|
||||
\node[above = of sync] (share) {Inhalt teilen};
|
||||
\node[above = 0.5cm of share] (discover) {Podcasts entdecken};
|
||||
\node[text width = 3cm, below = of sync] (create) {Listen erstellen und teilen};
|
||||
\node[text width = 3cm, below = 0.5cm of create] (popular) {Publisher:\\ Was ist beliebt?};
|
||||
|
||||
\node[hyperfocus, right = 3cm of sync, text width = 4cm] (PSE) {\underline{PSE\textsuperscript{2}}\begin{itemize}
|
||||
\item Schlankes Design
|
||||
\item Effizient
|
||||
\item Intuitiv
|
||||
\end{itemize}
|
||||
};
|
||||
|
||||
\draw[] (main) -- (sync);
|
||||
\draw[] (main) -- (share);
|
||||
\draw[] (main) |- (discover);
|
||||
\draw[] (main) -- (create);
|
||||
\draw[] (main) |- (popular);
|
||||
\draw[stealth-, thick] (sync.east) -- ($(PSE.north west) + (0, -0.3)$);
|
||||
|
||||
|
||||
\end{tikzpicture}
|
||||
|
||||
\end{figure}
|
||||
|
||||
\end{frame}
|
5377
01-pflichtenheft-kolloquium/tikz-uml.sty
Normal file
302
10-entwurfsheft/.gitignore
vendored
Normal file
|
@ -0,0 +1,302 @@
|
|||
## Core latex/pdflatex auxiliary files:
|
||||
*.aux
|
||||
*.lof
|
||||
*.log
|
||||
*.lot
|
||||
*.fls
|
||||
*.out
|
||||
*.toc
|
||||
*.fmt
|
||||
*.fot
|
||||
*.cb
|
||||
*.cb2
|
||||
.*.lb
|
||||
|
||||
## Intermediate documents:
|
||||
*.dvi
|
||||
*.xdv
|
||||
*-converted-to.*
|
||||
# these rules might exclude image files for figures etc.
|
||||
# *.ps
|
||||
# *.eps
|
||||
*.pdf
|
||||
!assets/*.pdf
|
||||
|
||||
## Generated if empty string is given at "Please type another file name for output:"
|
||||
.pdf
|
||||
|
||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||
*.bbl
|
||||
*.bcf
|
||||
*.blg
|
||||
*-blx.aux
|
||||
*-blx.bib
|
||||
*.run.xml
|
||||
|
||||
## Build tool auxiliary files:
|
||||
*.fdb_latexmk
|
||||
*.synctex
|
||||
*.synctex(busy)
|
||||
*.synctex.gz
|
||||
*.synctex.gz(busy)
|
||||
*.pdfsync
|
||||
|
||||
## Build tool directories for auxiliary files
|
||||
# latexrun
|
||||
latex.out/
|
||||
|
||||
## Auxiliary and intermediate files from other packages:
|
||||
# algorithms
|
||||
*.alg
|
||||
*.loa
|
||||
|
||||
# achemso
|
||||
acs-*.bib
|
||||
|
||||
# amsthm
|
||||
*.thm
|
||||
|
||||
# beamer
|
||||
*.nav
|
||||
*.pre
|
||||
*.snm
|
||||
*.vrb
|
||||
|
||||
# changes
|
||||
*.soc
|
||||
|
||||
# comment
|
||||
*.cut
|
||||
|
||||
# cprotect
|
||||
*.cpt
|
||||
|
||||
# elsarticle (documentclass of Elsevier journals)
|
||||
*.spl
|
||||
|
||||
# endnotes
|
||||
*.ent
|
||||
|
||||
# fixme
|
||||
*.lox
|
||||
|
||||
# feynmf/feynmp
|
||||
*.mf
|
||||
*.mp
|
||||
*.t[1-9]
|
||||
*.t[1-9][0-9]
|
||||
*.tfm
|
||||
|
||||
#(r)(e)ledmac/(r)(e)ledpar
|
||||
*.end
|
||||
*.?end
|
||||
*.[1-9]
|
||||
*.[1-9][0-9]
|
||||
*.[1-9][0-9][0-9]
|
||||
*.[1-9]R
|
||||
*.[1-9][0-9]R
|
||||
*.[1-9][0-9][0-9]R
|
||||
*.eledsec[1-9]
|
||||
*.eledsec[1-9]R
|
||||
*.eledsec[1-9][0-9]
|
||||
*.eledsec[1-9][0-9]R
|
||||
*.eledsec[1-9][0-9][0-9]
|
||||
*.eledsec[1-9][0-9][0-9]R
|
||||
|
||||
# glossaries
|
||||
*.acn
|
||||
*.acr
|
||||
*.glg
|
||||
*.glo
|
||||
*.gls
|
||||
*.glsdefs
|
||||
*.lzo
|
||||
*.lzs
|
||||
*.slg
|
||||
*.slo
|
||||
*.sls
|
||||
|
||||
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
||||
*.ist
|
||||
|
||||
# gnuplot
|
||||
*.gnuplot
|
||||
*.table
|
||||
|
||||
# gnuplottex
|
||||
*-gnuplottex-*
|
||||
|
||||
# gregoriotex
|
||||
*.gaux
|
||||
*.glog
|
||||
*.gtex
|
||||
|
||||
# htlatex
|
||||
*.4ct
|
||||
*.4tc
|
||||
*.idv
|
||||
*.lg
|
||||
*.trc
|
||||
*.xref
|
||||
|
||||
# hyperref
|
||||
*.brf
|
||||
|
||||
# knitr
|
||||
*-concordance.tex
|
||||
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
|
||||
# *.tikz
|
||||
*-tikzDictionary
|
||||
|
||||
# listings
|
||||
*.lol
|
||||
|
||||
# luatexja-ruby
|
||||
*.ltjruby
|
||||
|
||||
# makeidx
|
||||
*.idx
|
||||
*.ilg
|
||||
*.ind
|
||||
|
||||
# minitoc
|
||||
*.maf
|
||||
*.mlf
|
||||
*.mlt
|
||||
*.mtc[0-9]*
|
||||
*.slf[0-9]*
|
||||
*.slt[0-9]*
|
||||
*.stc[0-9]*
|
||||
|
||||
# minted
|
||||
_minted*
|
||||
*.pyg
|
||||
|
||||
# morewrites
|
||||
*.mw
|
||||
|
||||
# newpax
|
||||
*.newpax
|
||||
|
||||
# nomencl
|
||||
*.nlg
|
||||
*.nlo
|
||||
*.nls
|
||||
|
||||
# pax
|
||||
*.pax
|
||||
|
||||
# pdfpcnotes
|
||||
*.pdfpc
|
||||
|
||||
# sagetex
|
||||
*.sagetex.sage
|
||||
*.sagetex.py
|
||||
*.sagetex.scmd
|
||||
|
||||
# scrwfile
|
||||
*.wrt
|
||||
|
||||
# svg
|
||||
svg-inkscape/
|
||||
|
||||
# sympy
|
||||
*.sout
|
||||
*.sympy
|
||||
sympy-plots-for-*.tex/
|
||||
|
||||
# pdfcomment
|
||||
*.upa
|
||||
*.upb
|
||||
|
||||
# pythontex
|
||||
*.pytxcode
|
||||
pythontex-files-*/
|
||||
|
||||
# tcolorbox
|
||||
*.listing
|
||||
|
||||
# thmtools
|
||||
*.loe
|
||||
|
||||
# TikZ & PGF
|
||||
*.dpth
|
||||
*.md5
|
||||
*.auxlock
|
||||
|
||||
# titletoc
|
||||
*.ptc
|
||||
|
||||
# todonotes
|
||||
*.tdo
|
||||
|
||||
# vhistory
|
||||
*.hst
|
||||
*.ver
|
||||
|
||||
# easy-todo
|
||||
*.lod
|
||||
|
||||
# xcolor
|
||||
*.xcp
|
||||
|
||||
# xmpincl
|
||||
*.xmpi
|
||||
|
||||
# xindy
|
||||
*.xdy
|
||||
|
||||
# xypic precompiled matrices and outlines
|
||||
*.xyc
|
||||
*.xyd
|
||||
|
||||
# endfloat
|
||||
*.ttt
|
||||
*.fff
|
||||
|
||||
# Latexian
|
||||
TSWLatexianTemp*
|
||||
|
||||
## Editors:
|
||||
# WinEdt
|
||||
*.bak
|
||||
*.sav
|
||||
|
||||
# Texpad
|
||||
.texpadtmp
|
||||
|
||||
# LyX
|
||||
*.lyx~
|
||||
|
||||
# Kile
|
||||
*.backup
|
||||
|
||||
# gummi
|
||||
.*.swp
|
||||
|
||||
# KBibTeX
|
||||
*~[0-9]*
|
||||
|
||||
# TeXnicCenter
|
||||
*.tps
|
||||
|
||||
# auto folder when using emacs and auctex
|
||||
./auto/*
|
||||
*.el
|
||||
|
||||
# expex forward references with \gathertags
|
||||
*-tags.tex
|
||||
|
||||
# standalone packages
|
||||
*.sta
|
||||
|
||||
# Makeindex log files
|
||||
*.lpz
|
||||
|
||||
# xwatermark package
|
||||
*.xwm
|
||||
|
||||
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
|
||||
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
|
||||
# Uncomment the next line to have this generated file ignored.
|
||||
#*Notes.bib
|
36
10-entwurfsheft/.gitlab-ci.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
plantuml:
|
||||
stage: .pre
|
||||
image:
|
||||
name: plantuml/plantuml
|
||||
entrypoint: [""]
|
||||
script:
|
||||
- java -jar plantuml.jar -tpdf assets/diagrams/*.puml
|
||||
artifacts:
|
||||
paths:
|
||||
- assets
|
||||
|
||||
tex:
|
||||
stage: build
|
||||
image: texlive/texlive
|
||||
script:
|
||||
- mkdir public
|
||||
- make tex
|
||||
- mv *.pdf public
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
dependencies:
|
||||
- plantuml
|
||||
|
||||
pages:
|
||||
stage: deploy
|
||||
script:
|
||||
- echo Hello, World!
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
dependencies:
|
||||
- tex
|
||||
|
7
10-entwurfsheft/.latexmkrc
Normal file
|
@ -0,0 +1,7 @@
|
|||
# https://tex.stackexchange.com/questions/1226/how-to-make-latexmk-use-makeglossaries
|
||||
add_cus_dep('glo', 'gls', 0, 'makeglo2gls');
|
||||
add_cus_dep('acn', 'acr', 0, 'makeglo2gls');
|
||||
sub makeglo2gls {
|
||||
system("makeglossaries $_[0]");
|
||||
}
|
||||
|
18
10-entwurfsheft/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
|||
MAIN = entwurfsheft
|
||||
FLAGS = -pdf
|
||||
|
||||
all: clean compile
|
||||
compile: diagram tex
|
||||
clean: clean-diagram clean-tex
|
||||
|
||||
dev:
|
||||
latexmk $(FLAGS) -pvc $(MAIN)
|
||||
tex:
|
||||
latexmk $(FLAGS) $(MAIN)
|
||||
diagram:
|
||||
java -jar plantuml.jar -tpdf assets/diagrams/*.puml
|
||||
clean-tex:
|
||||
latexmk -C
|
||||
clean-diagram:
|
||||
find assets/diagrams -type f -not -name '*.puml' -delete
|
||||
|
31
10-entwurfsheft/README.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Entwurfsheft
|
||||
|
||||
> Systemdesign und -spezifikation
|
||||
|
||||
## Diagramme
|
||||
|
||||
Installiere [PlantUML](https://plantuml.com/starting) (oder über einen Paketmanager).
|
||||
|
||||
Arbeiten an Diagrammen mit Echtzeit-Vorschau (Anzeige wird beim Speichern der
|
||||
puml-Datei aktualisiert):
|
||||
```sh
|
||||
java -jar plantuml.jar -gui assets/classdiagram.puml
|
||||
|
||||
# bzw (wenn zu PATH hinzugefügt oder Linux)
|
||||
plantuml -gui assets/classdiagram.puml
|
||||
```
|
||||
|
||||
Bauen der Diagramme:
|
||||
```sh
|
||||
java -jar plantuml.jar -teps assets/*.puml
|
||||
|
||||
# bzw (wenn zu PATH hinzugefügt oder Linux)
|
||||
plantuml -teps assets/*.puml
|
||||
|
||||
# bzw über Makefile (Linux)
|
||||
make diagram
|
||||
|
||||
# oder zum Erstellen von Diagrammen und LaTeX:
|
||||
make
|
||||
```
|
||||
|
3
10-entwurfsheft/assets/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
diagrams/*
|
||||
!diagrams/*.puml
|
||||
|
BIN
10-entwurfsheft/assets/KIT_Deckblatt.pdf
Normal file
61
10-entwurfsheft/assets/diagrams/backendComponentDiagram.puml
Normal file
|
@ -0,0 +1,61 @@
|
|||
@startuml
|
||||
' skinparam linetype ortho
|
||||
|
||||
'#########################################################################
|
||||
'SubscriptionsAPI
|
||||
component SubscriptionsAPI {
|
||||
|
||||
component SubscriptionService
|
||||
component SubscriptionController
|
||||
component SubscriptionDataAccessLayer
|
||||
|
||||
portout "Webserver" as wSub
|
||||
portin "Database" as dSub
|
||||
}
|
||||
|
||||
dSub --0)- SubscriptionDataAccessLayer
|
||||
SubscriptionDataAccessLayer --0)- SubscriptionService
|
||||
SubscriptionService --0)- SubscriptionController
|
||||
SubscriptionController --0)- wSub
|
||||
|
||||
'#########################################################################
|
||||
|
||||
|
||||
'#########################################################################
|
||||
'EpisodeActionsAPI
|
||||
|
||||
component EpisodeActionsAPI {
|
||||
component EpisodeActionService
|
||||
component EpisodeActionController
|
||||
component EpisodeActionDataAccessLayer
|
||||
|
||||
portout "Webserver" as wEpisode
|
||||
portin "Database" as dEpisode
|
||||
}
|
||||
|
||||
dEpisode --0)- EpisodeActionDataAccessLayer
|
||||
EpisodeActionController --0)- wEpisode
|
||||
EpisodeActionDataAccessLayer --0)- EpisodeActionService
|
||||
EpisodeActionService --0)- EpisodeActionController
|
||||
|
||||
'#########################################################################
|
||||
|
||||
|
||||
'#########################################################################
|
||||
'AuthenticationAPI
|
||||
|
||||
component AuthenticationAPI {
|
||||
component AuthenticationService
|
||||
component AuthenticationController
|
||||
component AuthenticationDataAccessLayer
|
||||
|
||||
portout "Webserver" as wAuth
|
||||
portin "Database" as dAuth
|
||||
}
|
||||
|
||||
dAuth --0)- AuthenticationDataAccessLayer
|
||||
AuthenticationController --0)- wAuth
|
||||
AuthenticationDataAccessLayer --0)- AuthenticationService
|
||||
AuthenticationService --0)- AuthenticationController
|
||||
|
||||
@enduml
|
463
10-entwurfsheft/assets/diagrams/classdiagram.puml
Normal file
|
@ -0,0 +1,463 @@
|
|||
@startuml
|
||||
' skinparam linetype ortho
|
||||
' skinparam groupInheritance 2
|
||||
allowmixing
|
||||
|
||||
package subscriptionsAPI <<Frame>> {
|
||||
package subscriptionDataAccessLayer <<Frame>> {
|
||||
class SubscriptionDataAccessService <<@Repository>> {
|
||||
<<create>> SubscriptionDataAccessService(JpaTemplate jpaTemplate)
|
||||
int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
|
||||
List<String> getSubscriptions(String username)
|
||||
List<String> getSubscriptionsSince(String username, LocalDateTime time)
|
||||
int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
|
||||
int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
|
||||
List<SubscriptionTitles> getTitles(String username)
|
||||
}
|
||||
|
||||
interface SubscriptionDao {
|
||||
int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
|
||||
List<String> getSubscriptions(String username)
|
||||
List<String> getSubscriptionsSince(String username, LocalDateTime time)
|
||||
int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
|
||||
int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
|
||||
List<SubscriptionTitles> getTitles(String username)
|
||||
}
|
||||
}
|
||||
|
||||
package subscriptionService <<Frame>> {
|
||||
class SubscriptionService <<@Service>> {
|
||||
<<create>> SubscriptionService(SubscriptionDao subscriptionDao)
|
||||
int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
|
||||
List<String> getSubscriptions(String username)
|
||||
List<String> getSubscriptionsSince(String username, LocalDateTime time)
|
||||
int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
|
||||
int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
|
||||
List<SubscriptionTitles> getTitles(String username)
|
||||
}
|
||||
}
|
||||
|
||||
package subscriptionController <<Frame>> {
|
||||
class SubscriptionController <<@Controller>>{
|
||||
' @Autowired
|
||||
<<create>> SubscriptionController(SubscriptionService subscriptionService)
|
||||
' @GetMapping
|
||||
ResponseEntity<List<String>> getSubscriptions(String username, String deviceID, String functionJSONP)
|
||||
' @PutMapping
|
||||
ResponseEntity<String> uploadSubscriptions(String username, String deviceID, List<String> subscriptions)
|
||||
' @PostMapping
|
||||
ResponseEntity<SubscriptionDelta> applySubscriptionDelta(String username, String deviceID, SubscriptionDelta delta)
|
||||
' @GetMapping
|
||||
ResponseEntity<SubscriptionDelta> getSubscriptionDelta(String username, String deviceID, long since)
|
||||
ResponseEntity<List<SubscriptionTitles>> getTitles(String username, String deviceID)
|
||||
}
|
||||
|
||||
class SubscriptionTitles {
|
||||
<<create>> SubscriptionTitles(Subscription subscription, List<EpisodeActionPost> episodeTitles)
|
||||
Subscription getSubscription()
|
||||
List<EpisodeActionPost> getEpisodesTitles()
|
||||
}
|
||||
|
||||
class SubscriptionDelta {
|
||||
<<create>> SubscriptionDelta(List<String> add, List<String> remove)
|
||||
List<String> getRemove()
|
||||
LocalDate getTimestamp()
|
||||
List<List<String>> getUpdate_urls()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package episodeActionsAPI <<Frame>> {
|
||||
package episodeActionDataAccessLayer <<Frame>> {
|
||||
class EpisodeActionDataAccessService <<@Repository>> {
|
||||
<<create>> EpisodeActionDataAccessService (JpaTemplate jpaTemplate)
|
||||
long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
|
||||
List<EpisodeActionPost> getEpisodeActions(String username)
|
||||
List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
|
||||
List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
|
||||
List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
|
||||
}
|
||||
|
||||
interface EpisodeActionDao {
|
||||
long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
|
||||
List<EpisodeActionPost> getEpisodeActions(String username)
|
||||
List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
|
||||
List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
|
||||
List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
|
||||
}
|
||||
}
|
||||
|
||||
package episodeActionService <<Frame>> {
|
||||
class EpisodeActionService <<@Service>> {
|
||||
<<create>> EpisodeActionService (EpisodeActionDao episodeActionDao)
|
||||
LocalDateTime addEpisodeActions(String username, List<EpisodeActionPosts> episodeActionPosts)
|
||||
List<EpisodeActionPost> getEpisodeActions(String username)
|
||||
List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
|
||||
List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
|
||||
List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
|
||||
}
|
||||
}
|
||||
|
||||
package episodeActionController <<Frame>> {
|
||||
class EpisodeActionController <<@Controller>>{
|
||||
<<create>> EpisodeActionController (EpisodeActionService episodeActionService)
|
||||
ResponseEntity<EpisodeActionPostResponse> addEpisodeActions(String username, EpisodeActionPostRequest episodeActionPostRequest)
|
||||
ResponseEntity<EpisodeActionGetResponse> getEpisodeActions(String username, String deviceID, boolean aggregated)
|
||||
ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcast(String username, String podcastURL, String deviceID, boolean aggregated)
|
||||
ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsSince(String username, String deviceID, long since, boolean aggregated)
|
||||
ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcastSince(String username, String podcastURL, String deviceID, long since, boolean aggregated)
|
||||
}
|
||||
|
||||
class EpisodeActionPostResponse {
|
||||
<<create>> EpisodeActionPostResponse(List<Pair<String, String>> updateURLs)
|
||||
long getTimestamp()
|
||||
List<Pair<String, String>> getUpdatedURLs()
|
||||
}
|
||||
|
||||
class EpisodeActionPost {
|
||||
<<create>> EpisodeActionPost(String podcastURL, String episodeURL, Action action, LocalDateTime timestamp, int started, int position)
|
||||
String getPodcastURL()
|
||||
String getEpisodeURL()
|
||||
int getGUID()
|
||||
Action getAction()
|
||||
LocalDateTime getTimestamp()
|
||||
int getStarted()
|
||||
int getPosition()
|
||||
EpisodeAction getEpisodeAction()
|
||||
}
|
||||
|
||||
class EpisodeActionPostRequest {
|
||||
<<create>> EpisodeActionPostRequest(List<EpisodeActionPost> episodeActionPosts)
|
||||
List<EpisodeActionPost> getEpisodeActionPosts()
|
||||
}
|
||||
|
||||
class EpisodeActionGetResponse {
|
||||
<<create>> EpisodeActionGetResponse(List<EpisodeActionPost> episodeActionPosts)
|
||||
List<EpisodeActionPost> getEpisodeActionPosts()
|
||||
long getTimestamp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package authenticationAPI <<Frame>> {
|
||||
package authenticationDataAccessLayer <<Frame>> {
|
||||
' interface AuthenticationDao {
|
||||
' String login(String username)
|
||||
' int logout(String username)
|
||||
' }
|
||||
|
||||
' class AuthenticationDataAccessService <<@Respository>> {
|
||||
' <<create>> AuthenticationDataAccessService(JpaTemplate jpaTemplate)
|
||||
' String login(String username)
|
||||
' int logout(String username)
|
||||
' }
|
||||
|
||||
interface UserDetailsManager {
|
||||
void createUser(UserDetails userDetails)
|
||||
void changePassword(String oldPassword, String newPassword)
|
||||
void deleteUser(String username)
|
||||
void updateUser(UserDetails user)
|
||||
boolean userExists(String username)
|
||||
}
|
||||
note left
|
||||
Aus org.springframework.security.provisioning
|
||||
- liefert Methoden zum Erstellen neuer User
|
||||
und zum Aktualisieren bestehender.
|
||||
end note
|
||||
|
||||
class JdbcUserDetailsManager <<@Repository>> {
|
||||
<<create>> JdbcUserDetailsManager(DataSource dataSource)
|
||||
void createUser(UserDetails user)
|
||||
void changePassword(String oldPassword, String newPassword)
|
||||
void deleteUser(String username)
|
||||
void updateUser(UserDetails user)
|
||||
boolean userExists(String username)
|
||||
}
|
||||
note right
|
||||
User Management Service aus dem Paket
|
||||
org.springframework.security.provisioning
|
||||
der CRUD Operationen für User bereitstellt.
|
||||
Hier sind nur die relevanten Methoden modelliert.
|
||||
end note
|
||||
}
|
||||
|
||||
package authenticationService <<Frame>> {
|
||||
class AuthenticationService <<@Service>> {
|
||||
--
|
||||
<<create>> AuthenticationService(UserDetailsManager userDetailsManager)
|
||||
List<String> verifyLogin(String username)
|
||||
int logout(String username)
|
||||
int forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
|
||||
.. via JdbcUserDetailsManager ..
|
||||
int resetPassword(String username, RequestWithPassword requestWithPassword)
|
||||
int registerUser(UserDetails user)
|
||||
int changePassword(String username, ChangePasswordRequest changePasswordRequest)
|
||||
int deleteUser(String username, RequestWithPassword requestWithPassword)
|
||||
}
|
||||
|
||||
class JavaMailSenderImpl {}
|
||||
note left
|
||||
Aus org.springframework.mail.javamail.
|
||||
Implementierung des JavaMailSender Interfaces,
|
||||
welches das MailSender Interface durch Unterstützung
|
||||
von MIME Nachrichten erweitert.
|
||||
Das MailSender Interface definiert dabei eine
|
||||
Strategie zum Versenden einfacher Mails.
|
||||
Unterstützt sowohl JavaMail MimeMessages und
|
||||
Spring SimpleMailMessages.
|
||||
end note
|
||||
}
|
||||
|
||||
package authenticationController <<Frame>> {
|
||||
class AuthenticationController <<@Controller>> {
|
||||
<<create>> AuthenticationController(AuthenticationService authenticationService)
|
||||
ResponseEntity<List<String>> verifyLogin(String username)
|
||||
ResponseEntity<Integer> logout(String username)
|
||||
ResponseEntity<Integer> forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
|
||||
ResponseEntity<Integer> resetPassword(String username, RequestWithPassword requestWithPassword)
|
||||
ResponseEntity<Integer> registerUser(UserDetails user)
|
||||
ResponseEntity<Integer> changePassword(String username, ChangePasswordRequest changePasswordRequest)
|
||||
ResponseEntity<Integer> deleteUser(String username, RequestWithPassword requestWithPassword)
|
||||
}
|
||||
|
||||
class ChangePasswordRequest {
|
||||
<<create>> ChangePasswordRequest(String oldPassword, String newPassword)
|
||||
String getOldPassword()
|
||||
String getNewPassword()
|
||||
}
|
||||
|
||||
class ForgotPasswordRequest {
|
||||
<<create>> ForgotPasswordRequest(String email)
|
||||
String getEmail()
|
||||
}
|
||||
|
||||
class RequestWithPassword {
|
||||
<<create>> ResetPasswordRequest(String password)
|
||||
String getPassword()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package model <<Frame>> {
|
||||
class Subscription {
|
||||
<<create>> Subscription(String url, String title)
|
||||
int getID()
|
||||
String getURL()
|
||||
long getLastActionTimestamp()
|
||||
String getTitle()
|
||||
}
|
||||
|
||||
class SubscriptionAction {
|
||||
<<create>> SubscriptionAction(int userID, int subscriptionID)
|
||||
int getID()
|
||||
int getUserID()
|
||||
int getSubscriptionID()
|
||||
long getTimestamp()
|
||||
boolean getAdded()
|
||||
}
|
||||
|
||||
class Episode {
|
||||
<<create>> Episode(int subscriptionID, int id, String url, String title, String thumbnailURL, int total)
|
||||
int getSubscriptionID()
|
||||
int getID()
|
||||
int getGUID()
|
||||
String getURL()
|
||||
String getTitle()
|
||||
int getTotal()
|
||||
}
|
||||
|
||||
enum Action {
|
||||
Download
|
||||
Play
|
||||
Delete
|
||||
New
|
||||
Flattr
|
||||
String getJsonProperty()
|
||||
}
|
||||
|
||||
class EpisodeAction {
|
||||
<<create>> EpisodeAction(Action action, LocalDateTime timestamp, int started, int position)
|
||||
int getEpisodeID()
|
||||
Action getAction()
|
||||
long getTimestamp()
|
||||
int getStarted()
|
||||
int getPosition()
|
||||
void setEpisodeID()
|
||||
EpisodeActionPost getEpisodeActionPost(String podcastURL, String episodeURL)
|
||||
}
|
||||
|
||||
interface UserDetails {
|
||||
String getUsername()
|
||||
String getPassword()
|
||||
Collection<Authority> getAuthorities()
|
||||
boolean isAccountExpired()
|
||||
boolean isAccountLocked()
|
||||
boolean isCredentialsNonExpired()
|
||||
boolean isEnabled()
|
||||
}
|
||||
note left
|
||||
Aus org.springframework.security.core.userdetails.
|
||||
Wird für die Schnittstelle UserDetailsManager benötigt.
|
||||
Stellt wichtige Informationen eines Users bereit.
|
||||
Diese werden nur indirekt von Spring Security
|
||||
benutzt, indem sie vorher in Authentication Objekten
|
||||
gekapselt werden.
|
||||
end note
|
||||
|
||||
class User {
|
||||
--
|
||||
<<create>> User(String username, String password)
|
||||
int getID()
|
||||
String getSessionToken()
|
||||
boolean getEmailIsValidated()
|
||||
.. interface methods ..
|
||||
String getUsername()
|
||||
String getPassword()
|
||||
Collection<Authority> getAuthorities()
|
||||
boolean isAccountExpired()
|
||||
boolean isAccountLocked()
|
||||
boolean isCredentialsNonExpired()
|
||||
boolean isEnabled()
|
||||
}
|
||||
|
||||
interface GrantedAuthority {
|
||||
String getAuthority()
|
||||
}
|
||||
note right
|
||||
Aus org.springframework.security.core.
|
||||
Wird für die Schnittstelle UserDetails benötigt.
|
||||
Repräsentiert eine Autorisierung, die einem
|
||||
Authentication Objekt gewährt wird.
|
||||
end note
|
||||
|
||||
class Authority {
|
||||
<<create>> Authority()
|
||||
String getAuthority()
|
||||
}
|
||||
}
|
||||
|
||||
package util <<Frame>> {
|
||||
class RSSParser {
|
||||
<<create>> RSSParser(String subscriptionURL)
|
||||
String getSubscriptionTitle()
|
||||
List<Episode> getEpisodes()
|
||||
Episode getEpisodeForURL(String episodeURL)
|
||||
}
|
||||
note bottom
|
||||
Verwendet intern Spring um
|
||||
HTTP-Anfragen zu erstellen.
|
||||
end note
|
||||
|
||||
class CleanCronJob {
|
||||
<<create>> CleanCronJob(JdbcUserDetailsManager jdbcUserDetailsManager)
|
||||
void cleanInvalidUsers()
|
||||
}
|
||||
note bottom
|
||||
Hintergrundservice, der in periodischen Abständen
|
||||
Nutzer, die ihre E-Mail-Adresse nicht nach 24 Stunden
|
||||
bestätigt haben, wieder aus der Datenbank löscht.
|
||||
(Auf die Assoziation zu JdbcUserDetailsManager wird
|
||||
im Sinne der Übersichtlichkeit verzichtet.)
|
||||
end note
|
||||
|
||||
class ResponseEntity<T> {
|
||||
<<create>> ResponseEntity(T body, HttpStatusCode status)
|
||||
T getBody()
|
||||
HttpStatusCode getStatusCode()
|
||||
}
|
||||
note bottom
|
||||
Aus org.springframework.http.
|
||||
Erweitert die Klasse HttpEntity, welche
|
||||
ein HTTP Anfrage- oder Antwort-Objekt
|
||||
repräsentiert, durch einen HttpStatusCode.
|
||||
Wird von den Controller-Methoden als
|
||||
Rückgabewert verwendet.
|
||||
end note
|
||||
}
|
||||
|
||||
class SecurityConfigurationBasicAuth {
|
||||
<<create>> SecurityConfigurationBasicAuth()
|
||||
PasswordEncoder encoder()
|
||||
UserDetailsManager userDetailsService()
|
||||
SecuryFilterChain fiterChain(HTTPSecurity http) throws Excpetion
|
||||
}
|
||||
note top
|
||||
Erstellt einen Servlet Filter (springSecurityFilterChain)
|
||||
der für die gesamte Sicherheit zuständig ist (Schutz der URLs,
|
||||
Validierung von Anmeldedaten, Weiterleitung zur Anmeldung, etc.).
|
||||
end note
|
||||
|
||||
class PSEApplication {
|
||||
<<create>> PSEApplication()
|
||||
void main(String[] args)
|
||||
}
|
||||
|
||||
database Datenbank
|
||||
Datenbank <-[hidden]d- subscriptionsAPI
|
||||
Datenbank <-[hidden]d- episodeActionsAPI
|
||||
Datenbank <-[hidden]d- authenticationAPI
|
||||
() SQL as SQLSub
|
||||
() SQL as SQLAuth
|
||||
() SQL as SQLEpisode
|
||||
|
||||
Datenbank -- SQLSub
|
||||
Datenbank -- SQLAuth
|
||||
Datenbank -- SQLEpisode
|
||||
|
||||
SubscriptionController ..o PSEApplication
|
||||
AuthenticationController ..o PSEApplication
|
||||
EpisodeActionController ..o PSEApplication
|
||||
SecurityConfigurationBasicAuth ..o PSEApplication
|
||||
|
||||
PSEApplication --() HTTP
|
||||
|
||||
SQLSub )-- SubscriptionDataAccessService: JPA
|
||||
' SQLAuth )-- AuthenticationDataAccessService: JPA
|
||||
SQLAuth )-- JdbcUserDetailsManager: JDBC
|
||||
SQLEpisode )-- EpisodeActionDataAccessService: JPA
|
||||
|
||||
Subscription <. SubscriptionAction: ID
|
||||
' Subscription <.. SubscriptionDataAccessService: DB
|
||||
' SubscriptionAction <.. SubscriptionDataAccessService: DB
|
||||
SubscriptionService --o SubscriptionController
|
||||
SubscriptionDao <.. SubscriptionService: <<use>>
|
||||
Subscription --o SubscriptionTitles
|
||||
EpisodeActionPost -o SubscriptionTitles
|
||||
SubscriptionDao <|. SubscriptionDataAccessService: <<realize>>
|
||||
|
||||
' User <.. AuthenticationDataAccessService: DB
|
||||
' User <.. JdbcUserDetailsManager: DB
|
||||
UserDetailsManager <.. AuthenticationService: <<use>>
|
||||
' AuthenticationDao <.. AuthenticationService: <<use>>
|
||||
AuthenticationService --o AuthenticationController
|
||||
' AuthenticationDao <|. AuthenticationDataAccessService: <<realize>>
|
||||
UserDetailsManager <|. JdbcUserDetailsManager: <<realize>>
|
||||
UserDetailsManager <.. SecurityConfigurationBasicAuth: <<use>>
|
||||
UserDetails <|.. User: <<realize>>
|
||||
User -> Authority
|
||||
GrantedAuthority <|.. Authority: <<realize>>
|
||||
JavaMailSenderImpl <. AuthenticationService: <<use>>
|
||||
|
||||
Action <-- EpisodeAction
|
||||
EpisodeActionPost -o EpisodeActionGetResponse
|
||||
EpisodeActionPost -o EpisodeActionPostRequest
|
||||
EpisodeAction .> Episode: ID
|
||||
' EpisodeAction <.. EpisodeActionDataAccessService: DB
|
||||
' Episode <.. EpisodeActionDataAccessService: DB
|
||||
EpisodeActionDao <.. EpisodeActionService: <<use>>
|
||||
EpisodeActionService --o EpisodeActionController
|
||||
EpisodeActionDao <|. EpisodeActionDataAccessService: <<realize>>
|
||||
|
||||
RSSParser <. SubscriptionDataAccessService: <<use>>
|
||||
RSSParser <. EpisodeActionDataAccessService: <<use>>
|
||||
' JdbcUserDetailsManager <-- CleanCronJob
|
||||
|
||||
model .o Datenbank: ORM (User, SubscriptionAction, Subscription, EpisodeAction, Episode)
|
||||
' Datenbank o.. Subscription: ORM
|
||||
' Datenbank o.. SubscriptionAction: ORM
|
||||
' Datenbank o.. Episode: ORM
|
||||
' Datenbank o.. EpisodeAction: ORM
|
||||
' Datenbank o.. User: ORM
|
||||
|
||||
@enduml
|
53
10-entwurfsheft/assets/diagrams/componentdiagram.puml
Normal file
|
@ -0,0 +1,53 @@
|
|||
@startuml
|
||||
|
||||
[App] as app
|
||||
[VueRouter] as router
|
||||
[NavbarComponent] as navbar
|
||||
[LoginPage] as login_page
|
||||
[SubscriptionsPage] as abo_page
|
||||
[EpisodesPage] as episodes_page
|
||||
[SettingsPage] as settings_page
|
||||
[ForgotPasswordPage] as forgot_page
|
||||
[ResetPasswordPage] as reset_page
|
||||
note top
|
||||
Wird in der E-Mail zum Zurücksetzen des Passworts mit dem JWT-Token verlinkt.
|
||||
Sendet das alte und neue Passwort und den JWT an die API.
|
||||
end note
|
||||
[RegistrationPage] as registration_page
|
||||
|
||||
[SubscriptionComponent] as sub
|
||||
[EpisodeComponent] as episode
|
||||
[LastUpdateComponent] as last_update
|
||||
[PasswordValidatorComponent] as password
|
||||
|
||||
app --> router
|
||||
|
||||
app --> navbar
|
||||
router --> login_page
|
||||
router --> forgot_page
|
||||
router --> reset_page
|
||||
router --> registration_page
|
||||
router --> abo_page
|
||||
router --> episodes_page
|
||||
router --> settings_page
|
||||
|
||||
navbar -[hidden] router
|
||||
|
||||
episodes_page -[hidden] abo_page
|
||||
login_page -[hidden] forgot_page
|
||||
registration_page -[hidden] reset_page
|
||||
abo_page -[hidden] settings_page
|
||||
forgot_page -[hidden] episodes_page
|
||||
' forgot_page -[hidden] settings_page
|
||||
|
||||
abo_page --> sub
|
||||
episodes_page --> episode
|
||||
|
||||
sub --> last_update
|
||||
episode --> last_update
|
||||
|
||||
settings_page --> password
|
||||
reset_page --> password
|
||||
registration_page --> password
|
||||
|
||||
@enduml
|
78
10-entwurfsheft/assets/diagrams/db.puml
Normal file
|
@ -0,0 +1,78 @@
|
|||
@startuml
|
||||
' Type Symbol
|
||||
' Zero or One |o--
|
||||
' Exactly One ||--
|
||||
' Zero or Many }o--
|
||||
' One or Many }|--
|
||||
|
||||
skinparam linetype ortho
|
||||
|
||||
entity User {
|
||||
* int id <<unique>>
|
||||
* <u>String email</u>
|
||||
* String password
|
||||
* boolean verified
|
||||
* long created_at
|
||||
}
|
||||
|
||||
entity SubscriptionAction {
|
||||
* int id <<unique>>
|
||||
* <u>int user_id</u>
|
||||
* long timestamp
|
||||
* int subscription_id
|
||||
* boolean added
|
||||
}
|
||||
|
||||
entity Subscription {
|
||||
* int id <<unique>>
|
||||
* <u>String url</u>
|
||||
* long timestamp
|
||||
* String title
|
||||
}
|
||||
|
||||
entity Episode {
|
||||
* int id <<unique>>
|
||||
* <u>int guid <<unique>></u>
|
||||
* <u>String url</u>
|
||||
* String title
|
||||
* int total
|
||||
* int subscription_id
|
||||
}
|
||||
note right
|
||||
Wenn der Client eine GUID aus dem Feed mitsendet, wird
|
||||
diese statt der URL verwendet um die Episode zu finden.
|
||||
So wird die Episode auch noch gefunden, nachdem sich
|
||||
die URL geändert hat.
|
||||
end note
|
||||
note bottom of Episode
|
||||
Wenn für die Episoden-URL einer EpisodeAction noch keine Episode in der Datenbank steht,
|
||||
dann schreibe dafür ein Dummy-Objekt in Datenbank und lade asynchron die Episoden der Subscription.
|
||||
Ersetze dann die Dummy-Objekte durch die Episoden und setze den Timestamp der Subscription auf
|
||||
die aktuelle Zeit.
|
||||
Um DoS-Angriffe auf den Backend-Server abzuwenden, können die Episoden einer Subscription erst
|
||||
nach einer Stunde erneut gefetched werden. Bis dahin werden für EpisodeActions, die sich auf noch
|
||||
nicht geladene Episoden beziehen, nur Dummy-Objekte für die Episoden in die Datenbank geschrieben.
|
||||
Es sei noch darauf hingewiesen, dass diese Dummy-Episoden bei Anfragen nicht mit ausgegeben werden.
|
||||
end note
|
||||
|
||||
entity EpisodeAction {
|
||||
* int id <<unique>>
|
||||
* <u>int user_id</u>
|
||||
* int episode_id
|
||||
* long timestamp
|
||||
* int action
|
||||
* int started
|
||||
* int position
|
||||
}
|
||||
note right
|
||||
Speichere für jede Episode
|
||||
nur letzte Play-Action.
|
||||
endnote
|
||||
|
||||
User ||--o{ EpisodeAction
|
||||
User ||--o{ SubscriptionAction
|
||||
SubscriptionAction }|--|| Subscription
|
||||
EpisodeAction }|--|| Episode
|
||||
Subscription ||-right-|{ Episode
|
||||
|
||||
@enduml
|
59
10-entwurfsheft/assets/diagrams/deployment.puml
Normal file
|
@ -0,0 +1,59 @@
|
|||
@startuml
|
||||
|
||||
node "<<device>> \nBackend Server" as backendServer{
|
||||
database " <<database system>> \n MariaDB Server 10.6" as database {
|
||||
rectangle rectangle1 [
|
||||
<<schema>>
|
||||
User
|
||||
]
|
||||
rectangle rectangle2 [
|
||||
<<schema>>
|
||||
SubscriptionAction
|
||||
]
|
||||
rectangle rectangle3 [
|
||||
<<schema>>
|
||||
EpisodeAction
|
||||
]
|
||||
rectangle rectangle4 [
|
||||
<<schema>>
|
||||
Subscription
|
||||
]
|
||||
rectangle rectangle5 [
|
||||
<<schema>>
|
||||
Episode
|
||||
]
|
||||
}
|
||||
|
||||
node "<<framework>> \nJava Spring" as javaSpring{
|
||||
node " <<device>> \n Tomcat Webserver"
|
||||
}
|
||||
}
|
||||
|
||||
node "<<device>> \nFrontend" as frontendServer {
|
||||
|
||||
}
|
||||
|
||||
node "<<device>> \nEndgerät" as terminal {
|
||||
node "<<application>> \nBrowser" as browser
|
||||
node "<<application>> \nPodcatcher" as podcatcher
|
||||
}
|
||||
|
||||
backendServer "1" - "*" podcatcher
|
||||
|
||||
node "<<device>> \nFrontend Server" as frontendServer{
|
||||
node "<<framework>> \nVue.js" as vuejs {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
podcatcher -[hidden] browser
|
||||
|
||||
backendServer - "1" frontendServer
|
||||
|
||||
database "1" -- "1" javaSpring
|
||||
|
||||
browser "*" -- frontendServer
|
||||
|
||||
|
||||
|
||||
@enduml
|
|
@ -0,0 +1,41 @@
|
|||
@startuml
|
||||
|
||||
skinparam ParticipantPadding 30
|
||||
|
||||
participant AuthenticationController << (C, #ADD1B2) @Controller >>
|
||||
-> AuthenticationController: ""POST /api/2/auth/forgot.json"" \n//@RequestBody ForgotPasswordRequest forgotPasswordRequest// \n\n-> forgotPassword(//forgotPasswordRequest//)
|
||||
activate AuthenticationController
|
||||
participant AuthenticationService << (C, #ADD1B2) @Service >>
|
||||
AuthenticationController -> AuthenticationService: forgotPassword(//forgotPasswordRequest//)
|
||||
activate AuthenticationService
|
||||
participant JavaMailSenderImpl << (C, #ADD1B2) >>
|
||||
AuthenticationService -> JavaMailSenderImpl: create link to reset password with JWT as URL parameter \n-> send(SimpleMailMessage simpleMessage) with link
|
||||
activate JavaMailSenderImpl
|
||||
<<- JavaMailSenderImpl: sends email with link containing a JWT to reset password
|
||||
JavaMailSenderImpl --> AuthenticationService
|
||||
deactivate JavaMailSenderImpl
|
||||
AuthenticationService --> AuthenticationController: int indicating status
|
||||
deactivate AuthenticationService
|
||||
<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
|
||||
deactivate AuthenticationController
|
||||
||60||
|
||||
-> AuthenticationController: ""PUT /api/2/auth/{username}/resetpassword.json"" \n//@RequestParam String jwt// \n//@RequestBody ResetPasswordRequest resetPasswordRequest// \n\n-> login user (""username"") via JWT (//jwt//) \n-> resetPassword(""username"", //resetPasswordRequest//)
|
||||
activate AuthenticationController
|
||||
AuthenticationController -> AuthenticationService: resetPassword(""username"", //resetPasswordRequest//)
|
||||
activate AuthenticationService
|
||||
participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
|
||||
AuthenticationService -> JdbcUserDetailsManager: String oldPassword = //resetPasswordRequest//.getOldPassword() \nString newPassword = //resetPasswordRequest//.getNewPassword() \n-> changePassword(newPassword, oldPassword)
|
||||
activate JdbcUserDetailsManager
|
||||
database Database
|
||||
JdbcUserDetailsManager -> Database: change password of logged in user
|
||||
activate Database
|
||||
Database --> JdbcUserDetailsManager
|
||||
deactivate Database
|
||||
JdbcUserDetailsManager --> AuthenticationService: int indicating status
|
||||
deactivate JdbcUserDetailsManager
|
||||
AuthenticationService --> AuthenticationController: int indicating status
|
||||
deactivate AuthenticationService
|
||||
<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
|
||||
deactivate AuthenticationController
|
||||
|
||||
@enduml
|
|
@ -0,0 +1,38 @@
|
|||
@startuml
|
||||
|
||||
' title =**Get All Episode Actions**
|
||||
|
||||
participant EpisodeActionController << (C, #ADD1B2) @Controller >>
|
||||
-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("device") String deviceID// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActions(""username"", //deviceID//, //aggregated//)
|
||||
note right
|
||||
Die Parameter //deviceID// und //aggregated// werden ignoriert,
|
||||
da nicht zwischen Geräten unterschieden und für jede
|
||||
Episode sowieso nur die letzte Play-Action gespeichert
|
||||
wird. Dies gilt für alle GET-Anfragen der Episode Actions API.
|
||||
end note
|
||||
activate EpisodeActionController
|
||||
participant EpisodeActionService << (C, #ADD1B2) @Service >>
|
||||
EpisodeActionController -> EpisodeActionService: getEpisodeActions(""username"")
|
||||
activate EpisodeActionService
|
||||
participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
|
||||
EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActions(""username"")
|
||||
activate EpisodeActionDataAccessService
|
||||
EpisodeActionDataAccessService -> EpisodeActionDataAccessService: getEpisodeActionsSince(""username"", \nLocalDateTime.MIN.toEpochSecond(ZoneOffset.UTC))
|
||||
database Database
|
||||
activate EpisodeActionDataAccessService
|
||||
EpisodeActionDataAccessService -> Database: get all EpisodeActions for all subscribed podcasts
|
||||
activate Database
|
||||
Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than LocalDateTime.MIN (none)
|
||||
EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
|
||||
Database --> EpisodeActionDataAccessService
|
||||
deactivate Database
|
||||
EpisodeActionDataAccessService --> EpisodeActionDataAccessService: List<EpisodeActionPost> episodeActionPosts
|
||||
deactivate EpisodeActionDataAccessService
|
||||
EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
|
||||
deactivate EpisodeActionDataAccessService
|
||||
EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
|
||||
deactivate EpisodeActionService
|
||||
<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
|
||||
deactivate EpisodeActionController
|
||||
|
||||
@enduml
|
|
@ -0,0 +1,32 @@
|
|||
@startuml
|
||||
|
||||
' title =**Get Episode Actions of Podcast Since**
|
||||
|
||||
participant EpisodeActionController << (C, #ADD1B2) @Controller >>
|
||||
-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("podcast") String podcastURL// \n//@RequestParam("device") String deviceID// \n//@RequestParam("since") long since// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //deviceID//, //since//, //aggregated//)
|
||||
note right
|
||||
Die Parameter //deviceID// und //aggregated// werden ignoriert.
|
||||
Siehe Notiz in Sequenzdiagramm **Get All Episode Actions**.
|
||||
end note
|
||||
activate EpisodeActionController
|
||||
participant EpisodeActionService << (C, #ADD1B2) @Service >>
|
||||
EpisodeActionController -> EpisodeActionService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
|
||||
activate EpisodeActionService
|
||||
participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
|
||||
EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
|
||||
activate EpisodeActionDataAccessService
|
||||
database Database
|
||||
EpisodeActionDataAccessService -> Database: get all EpisodeActions the given podcast (//podcastURL//)
|
||||
activate Database
|
||||
Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than //since//
|
||||
EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
|
||||
Database --> EpisodeActionDataAccessService
|
||||
deactivate Database
|
||||
EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
|
||||
deactivate EpisodeActionDataAccessService
|
||||
EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
|
||||
deactivate EpisodeActionService
|
||||
<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
|
||||
deactivate EpisodeActionController
|
||||
|
||||
@enduml
|
|
@ -0,0 +1,38 @@
|
|||
@startuml
|
||||
|
||||
' title =**Get All Subscriptions**
|
||||
|
||||
participant SubscriptionController << (C, #ADD1B2) @Controller >>
|
||||
-> SubscriptionController: ""GET /subscriptions/{username}.json"" \n"" /subscriptions/{username}/{deviceid}.json"" \n//@RequestParam("jsonp") String functionJSONP// \n\n-> getSubscriptions(""username"", ""deviceid"", //functionJSONP//)
|
||||
activate SubscriptionController
|
||||
note right
|
||||
Die Parameter ""deviceid"" und
|
||||
//functionJSONP// werden ignoriert,
|
||||
da nicht zwischen Geräten unterschieden
|
||||
und JSONP nicht unterstützt wird.
|
||||
end note
|
||||
participant SubscriptionService << (C, #ADD1B2) @Service >>
|
||||
SubscriptionController -> SubscriptionService: getSubscriptions(""username"")
|
||||
activate SubscriptionService
|
||||
participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
|
||||
SubscriptionService -> SubscriptionDataAccessService: getSubscriptions(""username"")
|
||||
activate SubscriptionDataAccessService
|
||||
SubscriptionDataAccessService -> SubscriptionDataAccessService: getSubscriptionsSince(""username"", LocalDateTime.MIN)
|
||||
database Database
|
||||
activate SubscriptionDataAccessService
|
||||
SubscriptionDataAccessService -> Database: get all Subscriptions for ""username""
|
||||
activate Database
|
||||
Database --> SubscriptionDataAccessService: List<Subscription> subscriptions
|
||||
SubscriptionDataAccessService -> Database: get Podcasts from Subscriptions
|
||||
Database --> SubscriptionDataAccessService: List<Podcast> subscribedPodcasts
|
||||
deactivate Database
|
||||
SubscriptionDataAccessService --> SubscriptionDataAccessService: List<String> podcastURLs
|
||||
deactivate SubscriptionDataAccessService
|
||||
SubscriptionDataAccessService --> SubscriptionService: List<String> podcastURLs
|
||||
deactivate SubscriptionDataAccessService
|
||||
SubscriptionService --> SubscriptionController: List<String> podcastURLs
|
||||
deactivate SubscriptionService
|
||||
<-- SubscriptionController: ResponseEntity<List<String>> podcastURLs \n \n-> ""HTTP status code"" \n-> ""JSON""
|
||||
deactivate SubscriptionController
|
||||
|
||||
@enduml
|
|
@ -0,0 +1,26 @@
|
|||
@startuml
|
||||
|
||||
' title =**Register**
|
||||
|
||||
participant AuthenticationController << (C, #ADD1B2) @Controller >>
|
||||
-> AuthenticationController: ""POST /api/2/auth/register.json"" \n//@RequestBody UserDetails user// \n\n-> registerUser(//user//)
|
||||
activate AuthenticationController
|
||||
participant AuthenticationService << (C, #ADD1B2) @Service >>
|
||||
AuthenticationController -> AuthenticationService: registerUser(//user//)
|
||||
activate AuthenticationService
|
||||
participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
|
||||
AuthenticationService -> JdbcUserDetailsManager: createUser(//user//)
|
||||
activate JdbcUserDetailsManager
|
||||
database Database
|
||||
JdbcUserDetailsManager -> Database: create new User with given UserDetails (//user//)
|
||||
activate Database
|
||||
Database --> JdbcUserDetailsManager
|
||||
deactivate Database
|
||||
JdbcUserDetailsManager --> AuthenticationService: int indicating status
|
||||
deactivate JdbcUserDetailsManager
|
||||
AuthenticationService --> AuthenticationController: int indicating status
|
||||
deactivate AuthenticationService
|
||||
<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
|
||||
deactivate AuthenticationController
|
||||
|
||||
@enduml
|
|
@ -0,0 +1,38 @@
|
|||
@startuml
|
||||
|
||||
' title =**Upload Episode Actions**
|
||||
|
||||
participant EpisodeActionController << (C, #ADD1B2) @Controller >>
|
||||
-> EpisodeActionController: ""POST /api/2/episodes/{username}.json"" \n//@RequestBody EpisodeActionPostRequest episodeActionPostRequest// \n\n-> addEpisodeActions(""username"", //episodeActionPostRequest//)
|
||||
activate EpisodeActionController
|
||||
participant EpisodeActionService << (C, #ADD1B2) @Service >>
|
||||
EpisodeActionController -> EpisodeActionService: addEpisodeActions(""username"", \nepisodeActionPosts = //episodeActionPostRequest//.getEpisodeActionPosts())
|
||||
activate EpisodeActionService
|
||||
participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
|
||||
EpisodeActionService -> EpisodeActionDataAccessService: addEpisodeActions(""username"", episodeActionPosts)
|
||||
database Database
|
||||
activate EpisodeActionDataAccessService
|
||||
loop for each EpisodeActionPost in episodeActionPosts -> episodeAction = episodeActionPost.getEpisodeAction()
|
||||
opt episodeAction.getAction().equals(Action.PLAY)
|
||||
EpisodeActionDataAccessService -> Database: set episodeID field of episodeAction for this ""username"" via podcastURL and episodeURL
|
||||
activate Database
|
||||
Database --> EpisodeActionDataAccessService
|
||||
EpisodeActionDataAccessService -> Database: get last EpisodeAction with this episodeID if present
|
||||
Database --> EpisodeActionDataAccessService: Optional<EpisodeAction> lastEpisodeAction
|
||||
opt lastEpisodeAction.isPresent()
|
||||
EpisodeActionDataAccessService -> Database: replace lastEpisodeAction with episodeAction
|
||||
else else
|
||||
EpisodeActionDataAccessService -> Database: add episodeAction to DB as new entry
|
||||
end
|
||||
Database --> EpisodeActionDataAccessService
|
||||
deactivate Database
|
||||
end
|
||||
end
|
||||
EpisodeActionDataAccessService --> EpisodeActionService: long latestTimestamp
|
||||
deactivate EpisodeActionDataAccessService
|
||||
EpisodeActionService --> EpisodeActionController: LocalDateTime timestamp = LocalDateTime.ofEpochSecond(latestTimestamp, 0, ZoneOffset.UTC)
|
||||
deactivate EpisodeActionService
|
||||
<-- EpisodeActionController: ResponseEntity<EpisodeActionPostResponse> \n(with empty list for updateURLs) \n\n-> ""HTTP status code"" \n-> ""JSON""
|
||||
deactivate EpisodeActionController
|
||||
|
||||
@enduml
|
|
@ -0,0 +1,32 @@
|
|||
@startuml
|
||||
|
||||
' title =**Upload Subscriptions**
|
||||
|
||||
participant SubscriptionController << (C, #ADD1B2) @Controller >>
|
||||
-> SubscriptionController: ""PUT /subscriptions/{username}/{deviceid}.json"" \n//@RequestBody List<String> subscriptions// \n\n-> uploadSubscriptions(""username"", ""deviceid"", //subscriptions//)
|
||||
activate SubscriptionController
|
||||
participant SubscriptionService << (C, #ADD1B2) @Service >>
|
||||
SubscriptionController -> SubscriptionService: uploadSubscriptions(""username"", //subscriptions//)
|
||||
activate SubscriptionService
|
||||
participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
|
||||
SubscriptionService -> SubscriptionDataAccessService: uploadSubscriptions(""username"", //subscriptions//)
|
||||
activate SubscriptionDataAccessService
|
||||
database Database
|
||||
SubscriptionDataAccessService -> Database: delete all subsciptions of ""username""
|
||||
activate Database
|
||||
Database --> SubscriptionDataAccessService
|
||||
SubscriptionDataAccessService -> SubscriptionDataAccessService: addSubscriptions(""username"", //subscriptions//)
|
||||
activate SubscriptionDataAccessService
|
||||
SubscriptionDataAccessService -> Database: upload all subscriptions (//subscriptions//) for ""username""
|
||||
Database --> SubscriptionDataAccessService
|
||||
deactivate Database
|
||||
SubscriptionDataAccessService --> SubscriptionDataAccessService: int indicating status
|
||||
deactivate SubscriptionDataAccessService
|
||||
SubscriptionDataAccessService --> SubscriptionService: int indicating status
|
||||
deactivate SubscriptionDataAccessService
|
||||
SubscriptionService --> SubscriptionController: int indicating status
|
||||
deactivate SubscriptionService
|
||||
<-- SubscriptionController: ResponseEntity<String> with empty String for success \n\n-> ""HTTP status code"" \n-> ""JSON""
|
||||
deactivate SubscriptionController
|
||||
|
||||
@enduml
|
BIN
10-entwurfsheft/assets/episode.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
10-entwurfsheft/assets/help.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
10-entwurfsheft/assets/lastupdate.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
10-entwurfsheft/assets/logo.pdf
Normal file
211
10-entwurfsheft/assets/logo.svg
Normal file
|
@ -0,0 +1,211 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
version="1.2"
|
||||
width="87.589989mm"
|
||||
height="52.16547mm"
|
||||
viewBox="0 0 8758.9989 5216.547"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
fill-rule="evenodd"
|
||||
stroke-width="28.222"
|
||||
stroke-linejoin="round"
|
||||
xml:space="preserve"
|
||||
id="svg206"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
class="ClipPathGroup"
|
||||
id="defs8" />
|
||||
<defs
|
||||
id="defs51"><font
|
||||
id="EmbeddedFont_1"
|
||||
horiz-adv-x="2048"
|
||||
horiz-origin-x="0"
|
||||
horiz-origin-y="0"
|
||||
vert-origin-x="512"
|
||||
vert-origin-y="768"
|
||||
vert-adv-y="1024">
|
||||
<font-face
|
||||
font-family="Noto Sans Display Light embedded"
|
||||
units-per-em="2048"
|
||||
font-weight="normal"
|
||||
font-style="normal"
|
||||
ascent="2170"
|
||||
descent="609"
|
||||
id="font-face10" />
|
||||
<missing-glyph
|
||||
horiz-adv-x="2048"
|
||||
d="M 0,0 L 2047,0 2047,2047 0,2047 0,0 Z"
|
||||
id="missing-glyph12" />
|
||||
<glyph
|
||||
unicode="y"
|
||||
horiz-adv-x="927"
|
||||
d="M 2,1089 L 127,1089 367,413 C 388,352 407,298 422,250 437,203 449,161 457,124 L 463,124 C 471,156 483,196 498,246 513,296 530,350 551,409 L 786,1089 913,1089 453,-193 C 418,-290 377,-364 328,-416 279,-468 213,-494 131,-494 107,-494 84,-493 63,-490 43,-487 25,-482 8,-476 L 8,-377 C 23,-383 40,-387 57,-391 75,-394 95,-396 117,-396 170,-396 214,-378 249,-342 284,-307 314,-252 340,-179 L 403,4 2,1089 Z"
|
||||
id="glyph14" />
|
||||
<glyph
|
||||
unicode="t"
|
||||
horiz-adv-x="610"
|
||||
d="M 465,80 C 494,80 521,82 547,87 573,91 595,97 614,105 L 614,11 C 594,3 569,-5 541,-11 512,-17 481,-20 449,-20 363,-20 296,5 249,56 202,106 178,189 178,304 L 178,996 27,996 27,1061 178,1100 219,1350 295,1350 295,1090 608,1090 608,996 295,996 295,310 C 295,157 352,80 465,80 Z"
|
||||
id="glyph16" />
|
||||
<glyph
|
||||
unicode="s"
|
||||
horiz-adv-x="742"
|
||||
d="M 817,289 C 817,191 782,115 713,61 643,7 545,-20 418,-20 347,-20 284,-14 228,-1 173,12 126,29 88,50 L 88,162 C 134,138 186,118 244,102 301,86 360,78 420,78 520,78 592,96 636,133 680,169 702,218 702,281 702,341 679,387 632,419 585,451 515,484 422,519 359,542 303,565 255,589 207,613 169,643 142,680 116,717 102,768 102,832 102,919 136,987 204,1037 271,1086 361,1110 473,1110 535,1110 592,1104 646,1092 700,1080 750,1063 795,1043 L 754,946 C 713,964 667,980 617,993 568,1006 518,1012 469,1012 388,1012 326,997 283,967 239,937 217,893 217,836 217,792 228,758 249,733 270,707 301,686 342,668 383,650 433,630 492,609 553,585 608,562 657,537 707,512 745,481 774,443 803,405 817,353 817,289 Z"
|
||||
id="glyph18" />
|
||||
<glyph
|
||||
unicode="r"
|
||||
horiz-adv-x="583"
|
||||
d="M 596,1108 C 646,1108 692,1102 733,1091 L 717,983 C 674,995 632,1001 590,1001 497,1001 423,964 368,890 312,817 285,719 285,598 L 285,-1 168,-1 168,1089 266,1089 279,886 285,886 C 311,948 350,1000 402,1043 455,1086 520,1108 596,1108 Z"
|
||||
id="glyph20" />
|
||||
<glyph
|
||||
unicode="o"
|
||||
horiz-adv-x="927"
|
||||
d="M 1030,547 C 1030,433 1012,333 976,248 940,164 887,98 818,51 749,4 665,-20 565,-20 471,-20 390,3 322,50 253,96 201,162 164,247 127,333 109,433 109,547 109,723 150,861 232,961 315,1061 429,1110 575,1110 672,1110 755,1087 822,1040 890,993 941,927 977,842 1012,757 1030,659 1030,547 Z M 229,547 C 229,407 257,294 312,208 368,123 453,80 567,80 685,80 771,123 826,209 882,295 909,408 909,547 909,637 898,717 875,787 851,856 815,911 766,951 717,990 653,1010 573,1010 459,1010 373,969 315,887 258,805 229,692 229,547 Z"
|
||||
id="glyph22" />
|
||||
<glyph
|
||||
unicode="n"
|
||||
horiz-adv-x="847"
|
||||
d="M 633,1110 C 749,1110 838,1078 900,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1090 262,1090 279,901 287,901 C 314,962 357,1011 416,1051 474,1091 547,1110 633,1110 Z"
|
||||
id="glyph24" />
|
||||
<glyph
|
||||
unicode="m"
|
||||
horiz-adv-x="1430"
|
||||
d="M 1245,1110 C 1348,1110 1427,1080 1485,1018 1542,957 1571,860 1571,727 L 1571,1 1454,1 1454,723 C 1454,820 1434,892 1393,939 1352,986 1296,1010 1227,1010 1130,1010 1056,980 1005,919 953,858 928,764 928,637 L 928,1 811,1 811,723 C 811,820 791,892 750,939 709,986 653,1010 584,1010 487,1010 413,978 361,914 310,850 285,751 285,619 L 285,1 168,1 168,1090 262,1090 279,918 287,918 C 313,971 352,1016 403,1054 455,1092 521,1110 600,1110 675,1110 739,1093 791,1059 842,1025 879,975 899,908 L 907,908 C 936,972 980,1022 1038,1057 1097,1093 1166,1110 1245,1110 Z"
|
||||
id="glyph26" />
|
||||
<glyph
|
||||
unicode="i"
|
||||
horiz-adv-x="187"
|
||||
d="M 227,1493 C 279,1493 305,1464 305,1405 305,1345 279,1315 227,1315 175,1315 150,1345 150,1405 150,1464 175,1493 227,1493 Z M 285,1090 L 285,0 168,0 168,1090 285,1090 Z"
|
||||
id="glyph28" />
|
||||
<glyph
|
||||
unicode="h"
|
||||
horiz-adv-x="847"
|
||||
d="M 285,1059 C 285,1031 284,1003 283,977 281,951 279,926 276,901 L 285,901 C 312,962 355,1011 413,1051 471,1091 543,1110 629,1110 746,1110 836,1078 899,1014 962,950 993,850 993,713 L 993,1 877,1 877,705 C 877,809 854,885 810,935 766,985 701,1010 616,1010 395,1010 285,871 285,594 L 285,1 168,1 168,1557 285,1557 285,1059 Z"
|
||||
id="glyph30" />
|
||||
<glyph
|
||||
unicode="f"
|
||||
horiz-adv-x="689"
|
||||
d="M 575,995 L 332,995 332,-1 213,-1 213,995 27,995 27,1058 213,1093 213,1202 C 213,1445 316,1566 522,1566 559,1566 593,1563 623,1557 653,1551 680,1544 705,1536 L 678,1439 C 655,1448 630,1454 603,1460 577,1465 550,1468 524,1468 456,1468 407,1447 377,1405 347,1362 332,1295 332,1202 L 332,1089 575,1089 575,995 Z"
|
||||
id="glyph32" />
|
||||
<glyph
|
||||
unicode="e"
|
||||
horiz-adv-x="874"
|
||||
d="M 559,1110 C 646,1110 720,1089 779,1046 839,1003 883,944 913,869 943,794 958,708 958,611 L 958,531 229,531 C 231,386 262,275 325,198 387,121 476,82 592,82 656,82 712,88 759,100 806,111 858,130 915,156 L 915,50 C 865,25 814,7 764,-4 713,-15 655,-20 588,-20 434,-20 315,30 232,129 150,229 109,365 109,537 109,648 126,746 162,832 197,918 249,986 315,1036 382,1085 464,1110 559,1110 Z M 559,1012 C 465,1012 389,979 333,912 276,845 243,750 233,627 L 838,627 C 838,742 815,835 769,906 723,977 653,1012 559,1012 Z"
|
||||
id="glyph34" />
|
||||
<glyph
|
||||
unicode="d"
|
||||
horiz-adv-x="900"
|
||||
d="M 535,-20 C 398,-20 293,27 219,120 145,214 109,352 109,535 109,722 147,865 224,963 301,1061 408,1110 545,1110 629,1110 698,1090 752,1050 805,1010 845,961 872,904 L 881,904 C 879,935 878,970 876,1009 873,1048 872,1084 872,1117 L 872,1557 989,1557 989,0 895,0 879,191 872,191 C 845,132 805,82 751,41 697,0 625,-20 535,-20 Z M 553,80 C 669,80 752,119 801,195 850,271 875,382 875,527 L 875,545 C 875,695 850,810 801,890 752,970 671,1010 559,1010 451,1010 369,969 313,886 257,804 229,686 229,533 229,385 256,273 309,196 363,119 444,80 553,80 Z"
|
||||
id="glyph36" />
|
||||
<glyph
|
||||
unicode="c"
|
||||
horiz-adv-x="768"
|
||||
d="M 580,-20 C 429,-20 313,29 231,127 150,226 109,363 109,539 109,662 129,766 170,850 211,935 269,1000 343,1044 417,1088 504,1110 602,1110 651,1110 698,1106 742,1096 787,1087 825,1074 858,1057 L 825,957 C 791,972 754,984 714,993 673,1002 636,1006 600,1006 481,1006 390,964 326,881 261,798 229,685 229,541 229,405 258,294 314,210 371,126 459,84 580,84 630,84 678,90 723,101 768,112 809,125 846,142 L 846,37 C 812,20 773,6 729,-5 685,-15 636,-20 580,-20 Z"
|
||||
id="glyph38" />
|
||||
<glyph
|
||||
unicode="a"
|
||||
horiz-adv-x="822"
|
||||
d="M 535,1108 C 651,1108 737,1078 795,1018 852,958 881,863 881,734 L 881,0 793,0 772,185 766,185 C 729,123 684,74 631,36 578,-1 503,-20 408,-20 311,-20 233,6 176,59 119,111 90,187 90,285 90,394 132,477 215,533 298,589 420,621 580,629 L 764,639 764,715 C 764,822 744,897 705,942 665,987 606,1010 528,1010 477,1010 426,1002 378,987 329,972 281,953 231,928 L 195,1022 C 242,1047 295,1067 352,1084 410,1100 470,1108 535,1108 Z M 594,543 C 466,536 370,512 307,470 244,429 213,367 213,285 213,217 232,165 271,131 310,96 363,78 430,78 535,78 617,111 676,176 735,240 764,330 764,445 L 764,551 594,543 Z"
|
||||
id="glyph40" />
|
||||
<glyph
|
||||
unicode="S"
|
||||
horiz-adv-x="875"
|
||||
d="M 956,381 C 956,294 936,220 894,160 852,100 796,55 724,25 652,-5 571,-20 479,-20 396,-20 324,-14 262,-2 201,11 147,26 102,46 L 102,162 C 152,142 209,124 273,109 338,94 409,87 485,87 589,87 673,110 738,158 803,206 836,278 836,373 836,431 823,478 798,515 772,553 734,586 682,614 630,642 565,670 485,699 410,726 345,757 291,791 236,825 194,868 164,919 134,970 119,1035 119,1112 119,1192 138,1259 176,1314 214,1369 267,1411 333,1440 399,1469 474,1483 559,1483 626,1483 689,1476 750,1463 810,1449 868,1430 924,1405 L 883,1303 C 772,1352 663,1377 555,1377 462,1377 386,1354 328,1310 269,1266 240,1200 240,1114 240,1052 252,1001 278,964 303,926 340,895 389,869 438,843 498,817 567,791 648,762 717,731 775,698 833,664 878,623 909,573 941,523 956,459 956,381 Z"
|
||||
id="glyph42" />
|
||||
<glyph
|
||||
unicode="P"
|
||||
horiz-adv-x="848"
|
||||
d="M 539,1462 C 869,1462 1034,1325 1034,1049 1034,908 992,798 907,718 823,638 690,598 510,598 L 311,598 311,0 193,0 193,1462 539,1462 Z M 528,1358 L 311,1358 311,702 498,702 C 629,702 730,727 803,776 875,825 911,914 911,1043 911,1152 880,1232 818,1282 756,1333 659,1358 528,1358 Z"
|
||||
id="glyph44" />
|
||||
<glyph
|
||||
unicode="E"
|
||||
horiz-adv-x="769"
|
||||
d="M 950,0 L 193,0 193,1462 950,1462 950,1356 311,1356 311,821 913,821 913,715 311,715 311,107 950,107 950,0 Z"
|
||||
id="glyph46" />
|
||||
<glyph
|
||||
unicode=" "
|
||||
horiz-adv-x="503"
|
||||
id="glyph48" />
|
||||
</font></defs>
|
||||
<defs
|
||||
class="TextShapeIndex"
|
||||
id="defs55" />
|
||||
<defs
|
||||
class="EmbeddedBulletChars"
|
||||
id="defs87" />
|
||||
|
||||
<g
|
||||
id="id10"
|
||||
clip-path="none"
|
||||
transform="translate(-700.00001,-2550)">
|
||||
|
||||
<text
|
||||
class="SVGTextShape"
|
||||
id="text151"
|
||||
x="217.60002"
|
||||
y="-56.506969"
|
||||
style="letter-spacing:4.7625px;word-spacing:104.775px"><tspan
|
||||
class="TextParagraph"
|
||||
font-family="'Noto Sans Display Light', sans-serif"
|
||||
font-size="494px"
|
||||
font-weight="400"
|
||||
id="tspan149"><tspan
|
||||
class="TextPosition"
|
||||
x="650.59998"
|
||||
y="7647.4932"
|
||||
id="tspan147"><tspan
|
||||
fill="#808080"
|
||||
stroke="none"
|
||||
style="white-space:pre"
|
||||
id="tspan145"
|
||||
dx="2.1199999">Podcast Synchronisation made Efficient</tspan></tspan></tspan></text>
|
||||
</g><g
|
||||
id="g1277"
|
||||
transform="translate(-700.00001,-2550)"><path
|
||||
id="path131-3"
|
||||
d="m 6694.0006,4763 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1166 989.0352,986.0379 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.1649 -719.0259,-748.0163 12.7874,-421.0793 236.9242,-746.3999 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.9957,0 V 4763 Z"
|
||||
style="fill:#0084d1;fill-opacity:1"
|
||||
clip-path="none" /><path
|
||||
id="path131"
|
||||
d="m 6685.0183,2562.996 c -559.5515,4.407 -980.3924,428.0893 -986.038,985.9863 18.2894,552.8957 454.3127,974.1167 989.0352,986.038 v -235.0244 c -406.8751,-27.3888 -715.1078,-362.165 -719.0259,-748.0164 12.7874,-421.0792 236.9242,-746.3998 750.0318,-749.98 895.0688,1.4728 1915.5158,0 2730.996,0 V 2562.996 Z"
|
||||
style="fill:#0084d1;fill-opacity:1"
|
||||
clip-path="none" /></g><g
|
||||
id="g1263"
|
||||
transform="translate(-700.00001,-2550)"><path
|
||||
fill="none"
|
||||
stroke="#069a2e"
|
||||
stroke-width="265"
|
||||
stroke-linejoin="round"
|
||||
d="m 2793,5962 c 1283,0 429,-2762 1712,-2762"
|
||||
id="path124" /><path
|
||||
id="path110-6"
|
||||
d="M 3198.0212,6550 V 6300.0411 H 2448.0411 V 6050.0305 5550.0094 H 2198.0305 V 6300.0411 6550 H 2448.0411 2698 Z"
|
||||
style="fill:#069a2e;fill-opacity:1" /><path
|
||||
id="path110"
|
||||
d="m 4111.997,2550.0252 v 249.9589 h 749.9801 v 250.0106 500.0211 h 250.0106 v -750.0317 -249.9589 h -250.0106 -249.9589 z"
|
||||
style="fill:#069a2e;fill-opacity:1" /></g>
|
||||
<g
|
||||
id="g1249"
|
||||
transform="translate(-700.00001,-2550)"><path
|
||||
fill="#ff8000"
|
||||
stroke="none"
|
||||
d="M 2215,4164 C 2412.6918,3832.6035 2379.3124,3383.7591 2135.4189,3084.8193 1956.8564,2857.4026 1671.3097,2718.8851 1382,2721 c 0,-52.6667 0,-105.3333 0,-158 -60.1303,-1.0792 190.6585,-1.2724 121.9814,2.7933 434.6311,30.3756 832.6257,336.7309 974.9655,748.2365 148.7336,402.6249 41.0263,883.7477 -266.0719,1183.8452 C 1996.6852,4716.1853 1689.0048,4838.6187 1382,4830 c 0,-61.6667 0,-123.3333 0,-185 338.199,2.9253 666.226,-186.816 833,-481 z"
|
||||
id="path193" /><path
|
||||
fill="#ff8000"
|
||||
stroke="none"
|
||||
d="m 1936,3979 c 175.8129,-283.3241 59.7943,-700.6319 -239.8255,-849.407 -94.2713,-50.9942 -201.887,-77.9344 -309.1745,-74.593 0,-57 0,-114 0,-171 396.3865,-24.0968 777.5367,297.6517 818.5878,693.1841 44.0348,337.5467 -149.4277,694.9971 -466.4953,826.9493 -110.1027,49.0687 -231.5272,73.543 -352.0925,67.8666 0,-61.6667 0,-123.3333 0,-185 220.6353,7.5804 440.8554,-115.3286 549,-308 z"
|
||||
id="path186" /><path
|
||||
fill="#ff8000"
|
||||
stroke="none"
|
||||
d="m 1659,3822 c 86.3933,-138.0398 18.2474,-344.669 -134.6962,-402.3205 C 1483.44,3402.2177 1438.3524,3394.2432 1394,3398 c 0,-56.6667 0,-113.3333 0,-170 223.1964,-19.6143 444.7886,153.3254 478.4886,375.1817 32.646,181.6951 -54.6854,381.4331 -217.3127,472.2205 -78.2316,46.131 -170.3991,69.3119 -261.1759,62.5978 0,-58.3333 0,-116.6667 0,-175 105.6736,9.5509 212.8962,-49.2218 265,-141 z"
|
||||
id="path179" /><rect
|
||||
class="BoundingBox"
|
||||
stroke="none"
|
||||
fill="none"
|
||||
x="700"
|
||||
y="2550"
|
||||
width="501"
|
||||
height="4001"
|
||||
id="rect136"
|
||||
style="fill:#ff8000;fill-opacity:1" /></g>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 13 KiB |
BIN
10-entwurfsheft/assets/navbar.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
10-entwurfsheft/assets/password-margin.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
10-entwurfsheft/assets/password.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
10-entwurfsheft/assets/subscription.png
Normal file
After Width: | Height: | Size: 78 KiB |
90
10-entwurfsheft/entwurfsheft.tex
Normal file
|
@ -0,0 +1,90 @@
|
|||
% \documentclass[a4paper, UTF8, 12pt]{article}
|
||||
% \documentclass[a4paper, UTF8, 12pt]{scrbook}
|
||||
\documentclass[parskip=half, a4paper, 12pt]{scrartcl}
|
||||
|
||||
\usepackage[german]{babel}
|
||||
\usepackage[dvipsnames]{xcolor}
|
||||
% \usepackage{tikz}
|
||||
% \usetikzlibrary{positioning}
|
||||
% \usetikzlibrary{calc}
|
||||
% \usetikzlibrary{arrows}
|
||||
% \usetikzlibrary{intersections}
|
||||
% \usepackage{tikz-uml}
|
||||
% \usepackage{pgf-umlsd}
|
||||
% \usepgflibrary{arrows} % for pgf-umlsd
|
||||
% \tikzumlset{fill usecase=white}
|
||||
\usepackage[margin=2.5cm]{geometry}
|
||||
\usepackage{csquotes}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{amsmath}
|
||||
\usepackage{pdflscape}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{caption}
|
||||
\usepackage{subcaption}
|
||||
\usepackage{float}
|
||||
\usepackage{enumitem}
|
||||
% \usepackage{textpos}
|
||||
\usepackage{hyperref}
|
||||
\usepackage{fancyhdr}
|
||||
% \usepackage{multicol}
|
||||
\usepackage{rest-api}
|
||||
\usepackage{wrapfig}
|
||||
\usepackage{textcomp}
|
||||
\usepackage{ulem}
|
||||
|
||||
|
||||
\hypersetup{
|
||||
% ‘texdoc hyperref‘ for options
|
||||
pdftitle={
|
||||
PSE\textsuperscript{2}
|
||||
- Podcast Synchronisation made Efficient Pflichtenheft
|
||||
},
|
||||
bookmarks=true,
|
||||
}
|
||||
\usepackage{csquotes}
|
||||
\usepackage[toc]{glossaries}
|
||||
\usepackage{lastpage}
|
||||
|
||||
\include{sections/glossar}
|
||||
|
||||
\title{Pflichtenheft}
|
||||
\author{KIT Students et al}
|
||||
\date{2.12.2022}
|
||||
|
||||
\pagestyle{fancy}
|
||||
\setkomafont{pageheadfoot}{\footnotesize\scshape}
|
||||
\fancyhead{} % clear all header fields
|
||||
% \fancyhead[L]{Pflichtenheft}
|
||||
\fancyhead[L]{PSE\textsuperscript{2} - Podcast Synchronisation made Efficient}
|
||||
% \fancyhead[R]{2.12.2022}
|
||||
\fancyfoot{} % clear all footer fields
|
||||
\fancyfoot[R]{\thepage{} / \pageref{LastPage}}
|
||||
\fancyfoot[L]{Praxis der Softwareentwicklung}
|
||||
\fancyfoot[C]{}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\include{titlepage}
|
||||
\setcounter{page}{1}
|
||||
|
||||
\tableofcontents
|
||||
|
||||
\include{sections/einleitung}
|
||||
\newpage
|
||||
|
||||
\input{sections/aufbau}
|
||||
|
||||
\include{sections/structure}
|
||||
|
||||
\include{sections/backend}
|
||||
|
||||
\include{sections/frontend}
|
||||
|
||||
\include{sections/apidoc}
|
||||
|
||||
\include{sections/changes}
|
||||
|
||||
\printglossaries
|
||||
% \glsaddall
|
||||
|
||||
\end{document}
|
329
10-entwurfsheft/pgf-umlsd.sty
Normal file
|
@ -0,0 +1,329 @@
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Start of pgf-umlsd.sty
|
||||
%
|
||||
% Some macros for UML Sequence Diagrams.
|
||||
% Home page of project: http://pgf-umlsd.googlecode.com/
|
||||
% Author: Xu Yuan <xuyuan.cn@gmail.com>, Southeast University, China
|
||||
% Contributor: Nobel Huang <nobel1984@gmail.com>, Southeast University, China
|
||||
%
|
||||
% History:
|
||||
% v0.7 2012/03/05
|
||||
% - unify interface of call and callself
|
||||
% - non-instantaneous message
|
||||
% - bugfix: conflits with tikz library backgrounds
|
||||
% v0.6 2011/07/27
|
||||
% - Fix Issue 6 reported by frankmorgner@gmail.com
|
||||
% - diagram without a thread
|
||||
% - allows empty diagram
|
||||
% - New manual
|
||||
% v0.5 2009/09/30 Fix Issue 2 reported by vlado.handziski
|
||||
% - Nested callself is supported
|
||||
% - Rename sdloop and sdframe to sdblock
|
||||
% v0.4 2008/12/08 Fix Issue 1 reported by MathStuf:
|
||||
% Nested sdloop environment hides outer loop
|
||||
% v0.3 2008/11/10 in Berlin, fix for the PGF cvs version:
|
||||
% - the list items in \foreach are not evaluated by default now,
|
||||
% the `evaluate' opinion should be used
|
||||
% v0.2 2008/03/20 create project at http://pgf-umlsd.googlecode.com/
|
||||
% - use `shadows' library
|
||||
% Thanks for Dr. Ludger Humbert's <humbert@uni-wuppertal.de> feedback!
|
||||
% - reduce the parameter numbers, the user can write the content
|
||||
% of instance (such as no colon)
|
||||
% - the user can redefine the `inststyle'
|
||||
% - new option: switch underlining of the instance text
|
||||
% - new option: switch rounded corners
|
||||
% v0.1 2008/01/25 first release at http://www.fauskes.net/pgftikzexamples/
|
||||
%
|
||||
|
||||
\NeedsTeXFormat{LaTeX2e}[1999/12/01]
|
||||
\ProvidesPackage{pgf-umlsd}[2011/07/27 v0.6 Some LaTeX macros for UML
|
||||
Sequence Diagrams.]
|
||||
|
||||
\RequirePackage{tikz}
|
||||
\usetikzlibrary{arrows,shadows}
|
||||
|
||||
\RequirePackage{ifthen}
|
||||
|
||||
% Options
|
||||
% ? the instance name under line ?
|
||||
\newif\ifpgfumlsdunderline\pgfumlsdunderlinetrue
|
||||
\DeclareOption{underline}{\pgfumlsdunderlinetrue}
|
||||
\DeclareOption{underline=true}{\pgfumlsdunderlinetrue}
|
||||
\DeclareOption{underline=false}{\pgfumlsdunderlinefalse}
|
||||
% ? the instance box with rounded corners ?
|
||||
\newif\ifpgfumlsdroundedcorners\pgfumlsdroundedcornersfalse
|
||||
\DeclareOption{roundedcorners}{\pgfumlsdroundedcornerstrue}
|
||||
\DeclareOption{roundedcorners=true}{\pgfumlsdroundedcornerstrue}
|
||||
\DeclareOption{roundedcorners=false}{\pgfumlsdroundedcornersfalse}
|
||||
\ProcessOptions
|
||||
|
||||
% new counters
|
||||
\newcounter{preinst}
|
||||
\newcounter{instnum}
|
||||
\newcounter{threadnum}
|
||||
\newcounter{seqlevel} % level
|
||||
\newcounter{callevel}
|
||||
\newcounter{callselflevel}
|
||||
\newcounter{blocklevel}
|
||||
|
||||
% new an instance
|
||||
% Example:
|
||||
% \newinst[edge distance]{var}{name:class}
|
||||
\newcommand{\newinst}[3][0.2]{
|
||||
\stepcounter{instnum}
|
||||
\path (inst\thepreinst.east)+(#1,0) node[inststyle] (inst\theinstnum)
|
||||
{\ifpgfumlsdunderline
|
||||
\underline{#3}
|
||||
\else
|
||||
#3
|
||||
\fi};
|
||||
\path (inst\theinstnum)+(0,-0.5*\unitfactor) node (#2) {};
|
||||
\tikzstyle{instcolor#2}=[]
|
||||
\stepcounter{preinst}
|
||||
}
|
||||
|
||||
% new an instance thread
|
||||
% Example:
|
||||
% \newinst[color]{var}{name}{class}
|
||||
\newcommand{\newthread}[3][gray!30]{
|
||||
\newinst{#2}{#3}
|
||||
\stepcounter{threadnum}
|
||||
\node[below of=inst\theinstnum,node distance=0.8cm] (thread\thethreadnum) {};
|
||||
\tikzstyle{threadcolor\thethreadnum}=[fill=#1]
|
||||
\tikzstyle{instcolor#2}=[fill=#1]
|
||||
}
|
||||
|
||||
% draw running (thick) line, should not call directly
|
||||
\newcommand*{\drawthread}[2]{
|
||||
\begin{pgfonlayer}{umlsd@threadlayer}
|
||||
\draw[threadstyle] (#1.west) -- (#1.east) -- (#2.east) -- (#2.west) -- cycle;
|
||||
\end{pgfonlayer}
|
||||
}
|
||||
|
||||
% a function call
|
||||
% Example:
|
||||
% \begin{call}[height]{caller}{function}{callee}{return}
|
||||
% \end{call}
|
||||
\newenvironment{call}[5][1]{
|
||||
\ifthenelse{\equal{#2}{#4}}
|
||||
{
|
||||
\begin{callself}[#1]{#2}{#3}{#5}
|
||||
}
|
||||
{
|
||||
\begin{callanother}[#1]{#2}{#3}{#4}{#5}
|
||||
}
|
||||
}
|
||||
{
|
||||
\ifthenelse{\equal{\f\thecallevel}{\t\thecallevel}}
|
||||
{
|
||||
\end{callself}
|
||||
}
|
||||
{
|
||||
\end{callanother}
|
||||
}
|
||||
}
|
||||
|
||||
% function call to another instance
|
||||
% interal use only
|
||||
\newenvironment*{callanother}[5][1]{
|
||||
\stepcounter{seqlevel}
|
||||
\stepcounter{callevel} % push
|
||||
\path
|
||||
(#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {}
|
||||
(#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {};
|
||||
|
||||
\draw[->,>=triangle 60] ({cf\thecallevel}) -- (ct\thecallevel)
|
||||
node[midway, above] {#3};
|
||||
\def\l\thecallevel{#1}
|
||||
\def\f\thecallevel{#2}
|
||||
\def\t\thecallevel{#4}
|
||||
\def\returnvalue{#5}
|
||||
\tikzstyle{threadstyle}+=[instcolor#2]
|
||||
}
|
||||
{
|
||||
\addtocounter{seqlevel}{\l\thecallevel}
|
||||
\path
|
||||
(\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {}
|
||||
(\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rt\thecallevel) {};
|
||||
\draw[dashed,->,>=angle 60] ({rt\thecallevel}) -- (rf\thecallevel)
|
||||
node[midway, above]{\returnvalue};
|
||||
\drawthread{ct\thecallevel}{rt\thecallevel}
|
||||
\addtocounter{callevel}{-1} % pop
|
||||
}
|
||||
|
||||
% a function do not need call others
|
||||
% interal use only
|
||||
% Example:
|
||||
% \begin{callself}[height]{caller}{function}{return}
|
||||
% \end{callself}
|
||||
\newenvironment*{callself}[4][1]{
|
||||
\stepcounter{seqlevel}
|
||||
\stepcounter{callevel} % push
|
||||
\stepcounter{callselflevel}
|
||||
|
||||
\path
|
||||
(#2)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (sc\thecallevel) {}
|
||||
({sc\thecallevel}.east)+(0,-0.33*\unitfactor) node (scb\thecallevel) {};
|
||||
|
||||
\draw[->,>=triangle 60] ({sc\thecallevel}.east) -- ++(0.8,0)
|
||||
node[near start, above right] {#3} -- ++(0,-0.33*\unitfactor)
|
||||
-- (scb\thecallevel);
|
||||
\def\l\thecallevel{#1}
|
||||
\def\f\thecallevel{#2}
|
||||
\def\t\thecallevel{#2}
|
||||
\def\returnvalue{#4}
|
||||
\tikzstyle{threadstyle}+=[instcolor#2]
|
||||
}{
|
||||
\addtocounter{seqlevel}{\l\thecallevel}
|
||||
\path (\f\thecallevel)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.33*\unitfactor) node
|
||||
(sct\thecallevel) {};
|
||||
|
||||
\draw[dashed,->,>=angle 60] ({sct\thecallevel}.east) node
|
||||
(sce\thecallevel) {} -- ++(0.8,0) -- node[midway, right]{\returnvalue} ++(0,-0.33*\unitfactor) -- ++(-0.8,0);
|
||||
\drawthread{scb\thecallevel}{sce\thecallevel}
|
||||
\addtocounter{callevel}{-1} % pop
|
||||
\addtocounter{callselflevel}{-1}
|
||||
}
|
||||
|
||||
% message between threads
|
||||
% Example:
|
||||
% \mess[delay]{sender}{message content}{receiver}
|
||||
\newcommand{\mess}[4][0]{
|
||||
\stepcounter{seqlevel}
|
||||
\path
|
||||
(#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess from) {};
|
||||
\addtocounter{seqlevel}{#1}
|
||||
\path
|
||||
(#4)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess to) {};
|
||||
\draw[->,>=angle 60] (mess from) -- (mess to) node[midway, above]
|
||||
{#3};
|
||||
|
||||
\node (#3 from) at (mess from) {};
|
||||
\node (#3 to) at (mess to) {};
|
||||
}
|
||||
|
||||
\newenvironment{messcall}[4][1]{
|
||||
\stepcounter{seqlevel}
|
||||
\stepcounter{callevel} % push
|
||||
\path
|
||||
(#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {}
|
||||
(#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {};
|
||||
|
||||
\draw[->,>=angle 60] ({cf\thecallevel}) -- (ct\thecallevel)
|
||||
node[midway, above] {#3};
|
||||
\def\l\thecallevel{#1}
|
||||
\def\f\thecallevel{#2}
|
||||
\def\t\thecallevel{#4}
|
||||
\tikzstyle{threadstyle}+=[instcolor#2]
|
||||
}
|
||||
{
|
||||
\addtocounter{seqlevel}{\l\thecallevel}
|
||||
\path
|
||||
(\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {}
|
||||
(\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.3*\unitfactor) node (rt\thecallevel) {};
|
||||
\drawthread{ct\thecallevel}{rt\thecallevel}
|
||||
\addtocounter{callevel}{-1} % pop
|
||||
}
|
||||
|
||||
% In the situation of multi-threads, some objects are called at the
|
||||
% same time. Currently, we have to adjust the bias of thread line
|
||||
% manually. Possible parameters are: center, west, east
|
||||
\newcommand{\setthreadbias}[1]{\global\def\threadbias{#1}}
|
||||
|
||||
% This function makes the call earlier.
|
||||
\newcommand{\prelevel}{\addtocounter{seqlevel}{-1}}
|
||||
|
||||
% This function makes the call later.
|
||||
\newcommand{\postlevel}{\addtocounter{seqlevel}{+1}}
|
||||
|
||||
% a block box with caption
|
||||
% \begin{sdblock}[caption background color]{caption}{comments}
|
||||
% \end{sdblock}
|
||||
\newenvironment{sdblock}[3][white]{
|
||||
\stepcounter{seqlevel}
|
||||
\stepcounter{blocklevel} % push
|
||||
\coordinate (blockbeg\theblocklevel) at (0,-\theseqlevel*\unitfactor-\unitfactor);
|
||||
\stepcounter{seqlevel}
|
||||
\def\blockcolor\theblocklevel{#1}
|
||||
\def\blockname\theblocklevel{#2}
|
||||
\def\blockcomm\theblocklevel{#3}
|
||||
\begin{pgfinterruptboundingbox}
|
||||
}{
|
||||
\coordinate (blockend) at (0,-\theseqlevel*\unitfactor-2*\unitfactor);
|
||||
\path (current bounding box.east)+(0.2,0) node (boxeast) {}
|
||||
(current bounding box.west |- {blockbeg\theblocklevel}) + (-0.2,0)
|
||||
node (nw) {};
|
||||
\path (boxeast |- blockend) node (se) {};
|
||||
|
||||
% % title
|
||||
\node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel};
|
||||
\path (blocktitle.south east) + (0,0.2) node (set) {}
|
||||
(blocktitle.south east) + (-0.2,0) node (seb) {}
|
||||
(blocktitle.north east) + (0.2,0) node (comm) {};
|
||||
\draw[fill=\blockcolor\theblocklevel] (blocktitle.north west) -- (blocktitle.north east) --
|
||||
(set.center) -- (seb.center) -- (blocktitle.south west) -- cycle;
|
||||
\node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel};
|
||||
\node[blockcommentstyle] (blockcomment) at (comm) {\blockcomm\theblocklevel};
|
||||
|
||||
\coordinate (se) at (current bounding box.south east);
|
||||
\end{pgfinterruptboundingbox}
|
||||
|
||||
\draw (se) rectangle (nw);
|
||||
|
||||
\addtocounter{blocklevel}{-1} % pop
|
||||
\stepcounter{seqlevel}
|
||||
}
|
||||
|
||||
% the environment of sequence diagram
|
||||
\newenvironment{sequencediagram}{
|
||||
% declare layers
|
||||
\pgfdeclarelayer{umlsd@background}
|
||||
\pgfdeclarelayer{umlsd@threadlayer}
|
||||
\pgfsetlayers{umlsd@background,umlsd@threadlayer,main}
|
||||
|
||||
\begin{tikzpicture}
|
||||
\setlength{\unitlength}{1cm}
|
||||
\tikzstyle{sequence}=[coordinate]
|
||||
\tikzstyle{inststyle}=[rectangle, draw, anchor=west, minimum
|
||||
height=0.8cm, minimum width=1.6cm, fill=white,
|
||||
drop shadow={opacity=1,fill=black}]
|
||||
\ifpgfumlsdroundedcorners
|
||||
\tikzstyle{inststyle}+=[rounded corners=3mm]
|
||||
\fi
|
||||
\tikzstyle{blockstyle}=[anchor=north west]
|
||||
\tikzstyle{blockcommentstyle}=[anchor=north west, font=\small]
|
||||
\tikzstyle{dot}=[inner sep=0pt,fill=black,circle,minimum size=0.2pt]
|
||||
\global\def\unitfactor{0.6}
|
||||
\global\def\threadbias{center}
|
||||
% reset counters
|
||||
\setcounter{preinst}{0}
|
||||
\setcounter{instnum}{0}
|
||||
\setcounter{threadnum}{0}
|
||||
\setcounter{seqlevel}{0}
|
||||
\setcounter{callevel}{0}
|
||||
\setcounter{callselflevel}{0}
|
||||
\setcounter{blocklevel}{0}
|
||||
|
||||
% origin
|
||||
\node[coordinate] (inst0) {};
|
||||
}
|
||||
{
|
||||
\begin{pgfonlayer}{umlsd@background}
|
||||
\ifnum\c@instnum > 0
|
||||
\foreach \t [evaluate=\t] in {1,...,\theinstnum}{
|
||||
\draw[dotted] (inst\t) -- ++(0,-\theseqlevel*\unitfactor-2.2*\unitfactor);
|
||||
}
|
||||
\fi
|
||||
\ifnum\c@threadnum > 0
|
||||
\foreach \t [evaluate=\t] in {1,...,\thethreadnum}{
|
||||
\path (thread\t)+(0,-\theseqlevel*\unitfactor-0.1*\unitfactor) node (threadend) {};
|
||||
\tikzstyle{threadstyle}+=[threadcolor\t]
|
||||
\drawthread{thread\t}{threadend}
|
||||
}
|
||||
\fi
|
||||
\end{pgfonlayer}
|
||||
\end{tikzpicture}}
|
||||
|
||||
|
||||
%%% End of pgf-umlsd.sty
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
558
10-entwurfsheft/sections/apidoc.tex
Normal file
|
@ -0,0 +1,558 @@
|
|||
\newenvironment{urlParameter}
|
||||
{
|
||||
\newcommand{\urlParamItem}[2]
|
||||
{
|
||||
\rowcolor{\methodLightColor} ##1 & ##2 \\
|
||||
}
|
||||
\newcommand{\noUrlParameter}[1]
|
||||
{
|
||||
\small{\textit{##1}}
|
||||
}
|
||||
%\vspace{-0.61em}
|
||||
|
||||
\arrayrulecolor{\methodColor}
|
||||
|
||||
\begin{tabularx}{\textwidth}{X}
|
||||
\rowcolor{\methodLightColor!20}
|
||||
\textbf{URL-Parameter} \\ \hline
|
||||
\end{tabularx}
|
||||
|
||||
\tabularx{\textwidth}{l X}
|
||||
}
|
||||
|
||||
\newenvironment{pathParameter}
|
||||
{
|
||||
\newcommand{\pathParamItem}[2]
|
||||
{
|
||||
\rowcolor{\methodLightColor} ##1 & ##2 \\
|
||||
}
|
||||
\newcommand{\noPathParameter}[1]
|
||||
{
|
||||
\small{\textit{##1}}
|
||||
}
|
||||
%\vspace{-0.61em}
|
||||
|
||||
\arrayrulecolor{\methodColor}
|
||||
|
||||
\begin{tabularx}{\textwidth}{X}
|
||||
\rowcolor{\methodLightColor!20}
|
||||
\textbf{Pfad-Parameter} \\ \hline
|
||||
\end{tabularx}
|
||||
|
||||
\tabularx{\textwidth}{l X}
|
||||
}
|
||||
|
||||
\newenvironment{jsonKeys}
|
||||
{
|
||||
\newcommand{\jsonKeyItem}[2]
|
||||
{
|
||||
\rowcolor{\methodLightColor} ##1 & ##2 \\
|
||||
}
|
||||
\newcommand{\nojsonKeys}[1]
|
||||
{
|
||||
\small{\textit{##1}}
|
||||
}
|
||||
%\vspace{-0.61em}
|
||||
|
||||
\arrayrulecolor{\methodColor}
|
||||
|
||||
\begin{tabularx}{\textwidth}{X}
|
||||
\rowcolor{\methodLightColor!20}
|
||||
\textbf{Json-Keys} \\ \hline
|
||||
\end{tabularx}
|
||||
|
||||
\tabularx{\textwidth}{l X}
|
||||
}
|
||||
|
||||
\section{\Gls{api}}
|
||||
|
||||
\subsection{Hypertext Transfer Protocol}
|
||||
% könnte auch unter in die Sektion API
|
||||
|
||||
Das Hypertext Transfer Protocol (http) ist ein Protokoll zum übertragen von
|
||||
medialen Daten. Ein Webserver hört über den Port 80 auf Anfragen und antwortet.
|
||||
Eine Anfrage besteht aus einer Methode, einem Pfad, Kopfzeilen (\texttt{Header})
|
||||
und Inhalt (\texttt{Body}). Die Methode ist eine Konvention, um zu verdeutlichen
|
||||
was mit der Anfrage geschehen soll. Es können Daten abgefragt (\texttt{GET}),
|
||||
erstellt (\texttt{POST}), aktualisiert (\texttt{PUT}) oder gelöscht werden
|
||||
(\texttt{DELETE}). Der Pfad gibt an, für welche Daten die Methode gelten soll.
|
||||
Die Kopfzeilen beinhalten dabei Metadaten, wie Authentifikationen, \Glspl{cookie},
|
||||
Datentypen (MIME-Types), Sprache und das Anwenderprogramm.
|
||||
|
||||
Der Server antwortet mit einem Statuscode, Kopfzeilen und Inhalt. Der Statuscode
|
||||
teilt mit, ob die Anfrage erhalten wurde ($\geq$ 100), erfolgreich bearbeitet
|
||||
werden konnte ($\geq$ 200), eine Weiterleitung nötig ist ($\geq$ 300),
|
||||
die Anfrage einen Fehler enthält ($\geq$ 400) oder
|
||||
ein interner Serverfehler aufgetreten ist ($\geq$ 500). In den Kopfzeilen können
|
||||
Berechtigungen gesetzt werden, welche festlegen, wie mit den Daten
|
||||
umzugehen ist.
|
||||
|
||||
\newpage
|
||||
\subsection{Geräte} \label{Geräte}
|
||||
Die \Gls{gpodder}, welche wir für unser Produkt verwenden und erweitern, bietet eine gerätespezifische
|
||||
Synchronisation an. Diese bieten wir jedoch nicht an, denn wir synchronisieren Änderungen aller
|
||||
Geräte gleichwertig mit dem Nutzeraccount.
|
||||
Deshalb werden Geräte innerhalb der API ignoriert.
|
||||
|
||||
\subsection{Authentication API}\label{a:auth}
|
||||
|
||||
\subsubsection{Registrierung}\label{a:register}
|
||||
|
||||
\begin{apiRoute}{post}{/api/2/auth/register.json}
|
||||
{Registriert einen Nutzer mit einer E-Mail-Adresse und Passwort.
|
||||
Versendet E-Mail mit Bestätigungslink an die angegebene E-Mail-Adresse.}
|
||||
\begin{routeRequest}{application/json}
|
||||
\begin{routeRequestBody}
|
||||
{
|
||||
email: "jeff@example.com",
|
||||
password: "MyNameIsJeff"
|
||||
}
|
||||
\end{routeRequestBody}
|
||||
\end{routeRequest}
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}
|
||||
{OK: Nutzer wurde erfolgreich angelegt.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{400}
|
||||
{Bad Request: Fehler beim Parsen der Anfrage}
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\newpage
|
||||
|
||||
\subsubsection{Anmelden}\label{a:login}
|
||||
|
||||
\begin{apiRoute}{post}{/api/2/auth/\{username\}/login.json}
|
||||
{Gegebenen Nutzer des gegebenen Geräts mithilfe HTTP Basic Auth einloggen.}
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des einzuloggenden Nutzers}
|
||||
\end{pathParameter}
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}
|
||||
{OK: Die Responseheader haben ein gesetztes Session-ID \Gls{cookie}.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{400}
|
||||
{Bad Request: Der Client stellt einen \Gls{cookie} für einen falschen Nutzer bereit.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{401}
|
||||
{Unauthorized: Zugriff ohne Anmeldedaten}
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\subsubsection{Abmelden}\label{a:logout}
|
||||
|
||||
\begin{apiRoute}{post}{/api/2/auth/\{username\}/logout.json}
|
||||
{Löscht den \Gls{cookie} beim Client.}
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
|
||||
\end{pathParameter}
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}
|
||||
{OK: Falls der Client keinen \Gls{cookie} gesendet hat oder der Nutzer
|
||||
erfolgreich ausgeloggt wurde.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{400}
|
||||
{Bad Request: Der Client stellt einen \Gls{cookie} für den falschen Nutzer bereit.}
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\newpage
|
||||
|
||||
\subsubsection{Passwort ändern}\label{a:changepassword}
|
||||
|
||||
\begin{apiRoute}{put}{/api/2/auth/\{username\}/changepassword.json}
|
||||
{Passwort des gegebenen Nutzer ändern, indem altes und neues Passwort
|
||||
übergeben werden. }
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
|
||||
\end{pathParameter}
|
||||
\begin{routeRequest}{application/json}
|
||||
\begin{routeRequestBody}
|
||||
{
|
||||
password: "MyPasswordWasLeaked",
|
||||
new_password: "SoIMadeANewOne"
|
||||
}
|
||||
\end{routeRequestBody}
|
||||
\end{routeRequest}
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}
|
||||
{OK: Die Responseheader haben ein gesetztes Session-ID \Gls{cookie}.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{400}
|
||||
{Bad Request: Der Client stellt einen \Gls{cookie} für einen falschen Nutzer bereit.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{401}
|
||||
{Unauthorized: Zugriff ohne Anmeldedaten}
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\subsubsection{Passwort vergessen}\label{a:forgot}
|
||||
|
||||
\begin{apiRoute}{post}{/api/2/auth/forgot.json}
|
||||
{Sende eine E-Mail zum Zurücksetzen des Passworts. }
|
||||
\begin{routeRequest}{application/json}
|
||||
\begin{routeRequestBody}
|
||||
{
|
||||
email: "jeff@example.com"
|
||||
}
|
||||
\end{routeRequestBody}
|
||||
\end{routeRequest}
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}
|
||||
{OK: E-Mail wurde erfolgreich versendet.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{400}
|
||||
{Bad Request: Fehler beim Parsen der Anfrage}
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\newpage
|
||||
\subsubsection{Passwort zurücksetzen}\label{a:resetpassword}
|
||||
|
||||
\begin{apiRoute}{put}{/api/2/auth/\{username\}/resetpassword.json}
|
||||
{Passwort des gegebenen Nutzers ändern nachdem dieser sein Passwort
|
||||
vergessen hat. }
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
|
||||
\end{pathParameter}
|
||||
\begin{urlParameter}
|
||||
\urlParamItem{token}{JSON-Web-Token}
|
||||
\end{urlParameter}
|
||||
\begin{routeRequest}{application/json}
|
||||
\begin{routeRequestBody}
|
||||
{
|
||||
password: "APasswordIWontForgetAgain"
|
||||
}
|
||||
\end{routeRequestBody}
|
||||
\end{routeRequest}
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}
|
||||
{OK: Das Passwort wurde erfolgreich geändert.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{400}
|
||||
{Bad Request: Fehler beim Parsen der Anfragen. }
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{401}
|
||||
{Unauthorized: JWT ist ungültig. }
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\newpage
|
||||
\subsubsection{Account löschen}\label{a:delete}
|
||||
|
||||
\begin{apiRoute}{delete}{/api/2/auth/\{username\}/delete.json}
|
||||
{Der Account des gegebenen Nutzers wird gelöscht.}
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des zu löschenden Nutzers.}
|
||||
\end{pathParameter}
|
||||
\begin{routeRequest}{application/json}
|
||||
\begin{routeRequestBody}
|
||||
{
|
||||
password: "APasswordIWontHaveToRememberAnymore"
|
||||
}
|
||||
\end{routeRequestBody}
|
||||
\end{routeRequest}
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}
|
||||
{OK: Der Account des gegebenen Nutzers wurde erfolgreich gelöscht.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{400}
|
||||
{Bad Request: Der Client stellt einen \Gls{cookie} für einen falschen Nutzer bereit.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{401}
|
||||
{Unauthorized: Zugriff ohne Anmeldedaten}
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\newpage
|
||||
\subsection{Subscriptions API}\label{a:subs}
|
||||
\subsubsection{Abrufen aller \Glspl{abo}}\label{a:getSubs}
|
||||
|
||||
\begin{apiRoute}{get}{/subscriptions/\{username\}.json}{/subscriptions/\{username\}/\{deviceid\}.json}
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
|
||||
\pathParamItem{deviceid}{siehe~\nameref{Geräte}}
|
||||
\end{pathParameter}
|
||||
|
||||
\begin{urlParameter}
|
||||
\urlParamItem{jsonp}{\Gls{JSONP} wird nicht unterstützt und der Parameter entsprechend ignoriert.}
|
||||
\end{urlParameter}
|
||||
|
||||
\begin{routeResponse}{application/json}
|
||||
|
||||
\begin{routeResponseItem}{200}
|
||||
{OK: \Glspl{abo} werden im \Gls{json}-Format zurückgegeben.}
|
||||
\begin{routeResponseItemBody}
|
||||
[
|
||||
"http://example.org/feed.rss",
|
||||
"http://example.org/podcast.php",
|
||||
"http://example.org/foo"
|
||||
]
|
||||
\end{routeResponseItemBody}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{400}{Bad Request: falsches Format}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{401}
|
||||
{Unauthorized: falscher Nutzer oder nicht eingeloggt}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\newpage
|
||||
\subsubsection{Abrufen der Informationen aller \Glspl{abo}}\label{a:getTitles}
|
||||
|
||||
\begin{apiRoute}{get}{/subscriptions/titles/\{username\}.json}{/subscriptions/\{username\}/\{deviceid\}.json}
|
||||
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
|
||||
\end{pathParameter}
|
||||
\begin{routeResponse}{application/json}
|
||||
|
||||
\begin{routeResponseItem}{200}
|
||||
{OK: \Glspl{abo} werden im angefragten Format zurückgegeben. Dabei werden für ein \Gls{abo} nur die aktuellsten 20 \Glspl{episode} zurückgegeben.}
|
||||
\begin{routeResponseItemBody}
|
||||
[
|
||||
{
|
||||
"url": "http://example.com/podcast.php",
|
||||
"title": "This is a cool podcast"
|
||||
"timestamp": "2009-12-12T09:00:00",
|
||||
"episodes": [
|
||||
{
|
||||
"podcast": "http://example.org/podcast.php",
|
||||
"episode": "http://ftp.example.org/foo.ogg",
|
||||
"title": "Episode 1: My journy",
|
||||
"timestamp": "2009-12-12T09:00:00",
|
||||
"guid": "AU-20190814-1342-5100-A",
|
||||
"action": "play",
|
||||
"started": 15,
|
||||
"position": 120,
|
||||
"total": 500
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
\end{routeResponseItemBody}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{400}{Bad Request: falsches Format}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\end{routeResponse}
|
||||
|
||||
\end{apiRoute}
|
||||
\newpage
|
||||
|
||||
\subsubsection{\Glspl{abo} hochladen}\label{a:uploadSubs}
|
||||
|
||||
\begin{apiRoute}{put}{/subscriptions/\{username\}/\{deviceid\}.json}
|
||||
{Falls bereits \Glspl{abo} im Nutzeraccount vorhanden, werden diese
|
||||
zusammengeführt.}
|
||||
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
|
||||
\pathParamItem{deviceid}{siehe~\nameref{Geräte}}
|
||||
\end{pathParameter}
|
||||
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}
|
||||
{OK: \Glspl{abo} wurden aktualisiert und leerer String wird zurückgegeben.}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{400}{Bad Request: falsches Format}
|
||||
\end{routeResponseItem}
|
||||
|
||||
\begin{routeResponseItem}{401}{Unauthorized: falscher Nutzer}
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\subsubsection{Abrufen von \Gls{abo}-Änderungen}\label{a:getSubDelta}
|
||||
|
||||
\begin{apiRoute}{get}{/api/2/subscriptions/\{username\}/\{deviceid\}.json}
|
||||
{}
|
||||
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
|
||||
\pathParamItem{deviceid}{siehe~\nameref{Geräte}}
|
||||
\end{pathParameter}
|
||||
|
||||
\begin{urlParameter}
|
||||
\urlParamItem{since}{Timestamp-Wert der letzten Antwort}
|
||||
\end{urlParameter}
|
||||
|
||||
\begin{routeResponse}{application/json}
|
||||
|
||||
\begin{routeResponseItemBody}
|
||||
{
|
||||
"add": [
|
||||
"http://example.com/feed.rss",
|
||||
"http://example.org/podcast.php"
|
||||
],
|
||||
"remove": ["http://example.net/foo.xml"],
|
||||
"timestamp": 12347
|
||||
}
|
||||
\end{routeResponseItemBody}
|
||||
\end{routeResponse}
|
||||
|
||||
\end{apiRoute}
|
||||
|
||||
\newpage
|
||||
\subsubsection{Änderungen der \Glspl{abo} hochladen}\label{a:applySubDelta}
|
||||
|
||||
\begin{apiRoute}{post}{/api/2/subscriptions/\{username\}/\{deviceid\}.json}
|
||||
{}
|
||||
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
|
||||
\pathParamItem{deviceid}{siehe~\nameref{Geräte}}
|
||||
\end{pathParameter}
|
||||
|
||||
\begin{routeRequest}{application/json}
|
||||
\begin{routeRequestBody}
|
||||
{
|
||||
"add": [
|
||||
"http://example.com/feed.rss",
|
||||
"http://example.org/podcast.php"
|
||||
],
|
||||
"remove": ["http://example.net/foo.xml"]
|
||||
}
|
||||
\end{routeRequestBody}
|
||||
\end{routeRequest}
|
||||
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}{OK: \Glspl{abo} wurden aktualisiert.}
|
||||
\begin{routeResponseItemBody}
|
||||
{
|
||||
"timestamp": 1337,
|
||||
"update_urls": []
|
||||
}
|
||||
\end{routeResponseItemBody}
|
||||
``update\textunderscore urls'' wird nicht bereitgestellt, deshalb
|
||||
wird eine leere Liste zurückgegeben.
|
||||
\end{routeResponseItem}
|
||||
\begin{routeResponseItem}{400}{Bad Request: falsches Format}
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\newpage
|
||||
\subsection{Episode Action API}\label{a:episodeActions}
|
||||
|
||||
\subsubsection{Episode Actions hochladen}\label{a:uploadEpisodeActions}
|
||||
|
||||
\begin{apiRoute}{post}{/api/2/episodes/\{username\}.json}
|
||||
{}
|
||||
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
|
||||
\end{pathParameter}
|
||||
|
||||
\begin{routeRequest}
|
||||
|
||||
\begin{routeRequestBody}
|
||||
POST /api/2/episodes/some-user.json
|
||||
[
|
||||
{
|
||||
"podcast": "http://example.org/podcast.php",
|
||||
"episode": "http://ftp.example.org/foo.ogg",
|
||||
"title": "Episode 1: My journey",
|
||||
"timestamp": "2009-12-12T09:00:00"
|
||||
"guid": "AU-20190814-1342-5100-A",
|
||||
"action": "play",
|
||||
"started": 15,
|
||||
"position": 120,
|
||||
"total": 500
|
||||
}
|
||||
]
|
||||
|
||||
\end{routeRequestBody}
|
||||
|
||||
\end{routeRequest}
|
||||
|
||||
\begin{jsonKeys}
|
||||
\jsonKeyItem{podcast}{Feed-URL des \Glspl{podcast} zu welchem die \Gls{episode} gehört (erforderlich)}
|
||||
\jsonKeyItem{episode}{Medien-URL der \Gls{episode} (erforderlich)}
|
||||
\jsonKeyItem{device}{Geräte-ID auf welcher die Aktion stattfand.}
|
||||
\jsonKeyItem{action}{Eins von: download, play, delete, new (erforderlich)}
|
||||
\jsonKeyItem{timestamp}{UTC-Timestamp im ISO 8601 Format, wann die Aktion stattfand}
|
||||
\jsonKeyItem{started}{Position in Sekunden, an welcher das Anhören der \Gls{episode} gestartet wurde (nur bei Aktion: play)}
|
||||
\jsonKeyItem{position}{Position in Sekunden, an welcher das Anhören der \Gls{episode} gestoppt wurde (nur bei Aktion: play)}
|
||||
\jsonKeyItem{total}{Länge der \Gls{episode} (nur bei Aktion: play)}
|
||||
|
||||
\end{jsonKeys}
|
||||
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}{OK}
|
||||
\begin{routeResponseItemBody}
|
||||
{
|
||||
"timestamp": 1337,
|
||||
"update_urls": []
|
||||
}
|
||||
\end{routeResponseItemBody}
|
||||
``update\textunderscore urls'' wird nicht bereitgestellt, deshalb
|
||||
wird eine leere Liste zurückgegeben.
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
||||
\subsubsection{Abrufen von Episode Actions}\label{a:getEpisodeActions}
|
||||
|
||||
\begin{apiRoute}{get}{/api/2/episodes/\{username\}.json}
|
||||
{}
|
||||
|
||||
\begin{pathParameter}
|
||||
\pathParamItem{username}{Nutzername des betreffenden Nutzers}
|
||||
\end{pathParameter}
|
||||
|
||||
\begin{urlParameter}
|
||||
\urlParamItem{podcast (string)}{URL des \Glspl{podcast}; falls gesetzt, werden nur Aktionen der \Glspl{episode} des gegebenen \Glspl{podcast} zurückgegeben.}
|
||||
\urlParamItem{device (string)}{Device-ID; siehe~\nameref{Geräte}}
|
||||
\urlParamItem{since (int)}{Nur \Glspl{episode}-Aktionen ab dem gegebenen Timestamp werden zurückgegeben.}
|
||||
\urlParamItem{aggregated (bool)}{Wird ignoriert. }
|
||||
\end{urlParameter}
|
||||
|
||||
\begin{routeResponse}{application/json}
|
||||
\begin{routeResponseItem}{200}{OK}
|
||||
\begin{routeResponseItemBody}
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"podcast": "http://example.org/podcast.php",
|
||||
"episode": "http://ftp.example.org/foo.ogg",
|
||||
"title": "Episode 1: My journey",
|
||||
"timestamp": "2009-12-12T09:00:00"
|
||||
"guid": "AU-20190814-1342-5100-A",
|
||||
"action": "play",
|
||||
"started": 15,
|
||||
"position": 120,
|
||||
"total": 500
|
||||
}
|
||||
],
|
||||
"timestamp": 12345
|
||||
}
|
||||
\end{routeResponseItemBody}
|
||||
\end{routeResponseItem}
|
||||
\end{routeResponse}
|
||||
\end{apiRoute}
|
||||
|
89
10-entwurfsheft/sections/aufbau.tex
Normal file
|
@ -0,0 +1,89 @@
|
|||
\section{Aufbau}
|
||||
|
||||
\subsection{Architektur}
|
||||
|
||||
\subsubsection{Aufteilung in Pakete}
|
||||
|
||||
Das Backend wird in Pakete aufgeteilt, die den einzelnen implementierten
|
||||
\Glspl{api} der gpodder.net \Gls{api} entsprechen.
|
||||
Dies entspricht hier den \Glspl{api}: Subscriptions, Episode Actions und Authentication.
|
||||
Außerdem gibt es ein Model-Paket, welches die in den Logikschichten verwendeten Objekte modelliert.
|
||||
|
||||
Für den Webserver selbst werden die \Glspl{api} um zusätzliche Funktionen erweitert. Denn die vorhandenen \Glspl{api} bieten nicht alle Funktionalitäten, die der Webserver benötigt, um die im Pflichtenheft beschriebenen Kriterien zu erfüllen.
|
||||
% (TODO: WebAPI bestimmen)
|
||||
|
||||
\subsubsection{Die Architektur in den Paketen}
|
||||
|
||||
In den Paketen selber herrscht eine 3-schichtige Architektur aus den Schichten: Controller, Service und Data-Access (siehe \ref{DAO_Pattern}).
|
||||
|
||||
Die Controller-Schicht nimmt die Anfragen des Clients entgegen, lässt diese in den untergeordneten Schichten verarbeiten und gibt den Status der abgeschlossenen Handlung an den Client zurück.
|
||||
|
||||
Die Service-Schicht ist die \Gls{business} des Programmes und überprüft bspw. Eingaben oder verschickt E-Mails. Sollte ein \Gls{db}aufruf nötig sein, so ruft der Service die Data-Access-Schicht auf und übergibt ihr die nötigen Informationen, was gespeichert, gelöscht, aktualisiert oder gelesen werden soll.
|
||||
|
||||
Die Data-Access-Schicht ist für den Datenzugriff auf \Glspl{db} verantwortlich. Alle verantwortlichen Klassen für einen solchen Zugriff folgen dem \Gls{crud}-Prinzip.
|
||||
\Gls{crud} steht für die Funktionen Create (erschaffen), Read (lesen), Update (aktualisieren) und Delete (löschen). Entsprechend können Einträge in einer \Gls{db} auch nur erschaffen, gelesen, aktualisiert und gelöscht werden.
|
||||
|
||||
\subsubsection{Das Model-Paket}\label{p:model}
|
||||
|
||||
In einem globalen Model-Paket befinden sich alle Klassen, die für die Modellierungen von Objekten zuständig sind.
|
||||
Diese Objekte werden später in \Gls{db}abfragen gelesen und mittels objektrelationaler Abbildung (siehe \ref{t:orm}) gespeichert.
|
||||
In einer Antwort an den Client werden die Objekte, falls benötigt, als Antwort-Klassen gewrappt im \Gls{json}-Format zurückgeschickt.
|
||||
Auch kann der Client in einer Anfrage ein Objekt im \Gls{json}-Format übergeben, welches dann mithilfe von Spring als \Gls{java}-Objekt der korrespondierenden Anfrage-Klasse interpretiert wird.
|
||||
Aus diesem wird dann in Controller- und Service-Schicht das Objekt der entsprechenden Model-Klasse extrahiert.
|
||||
|
||||
\subsubsection{Die Datenhaltungsschicht}
|
||||
|
||||
Mit den Paketen ist bereits eine 3-schichtige Architektur aufgebaut.
|
||||
Damit Daten aber auch gelesen und gespeichert werden können ist eine vierte globale Schicht nötig - die Datenhaltungsschicht.
|
||||
|
||||
Die Datenhaltungsschicht ist für die persistente Speicherung aller Daten zuständig.
|
||||
Diese werden meist (wie in diesem Fall) in einer \Gls{db} gespeichert.
|
||||
Der Zugriff auf die Datenhaltungsschicht erfolgt gemäß der intransparenten Schichtenarchitektur nur über die Data-Access-Schicht der Pakete.
|
||||
|
||||
Der Vorteil dieser mehrschichtigen Architektur ist die klare Strukturierung des Programmes, womit der Code leserlicher und einfacher zu warten ist.
|
||||
|
||||
\begin{landscape}
|
||||
|
||||
\subsection{Klassendiagramm Backend}
|
||||
Das Klassendiagramm zeigt alle für den Entwurf relevanten Klassen des Backends mit ihren öffentlichen Methoden.
|
||||
Weiter zeigt das Diagramm die Aufteilung der Klassen in Pakete sowie schemenhaft dargestellte Verbindungen zu \Gls{db} und Webserver.
|
||||
|
||||
% \input{assets/diagrams/classdiagram.latex}
|
||||
\includegraphics[width=\linewidth]{assets/diagrams/classdiagram}
|
||||
\end{landscape}
|
||||
|
||||
\subsection{Sequenzdiagramme}
|
||||
|
||||
\subsubsection{Authentication \Gls{api}}
|
||||
\subsubsection*{Registrierung \scriptsize{(\ref{a:register})}}
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-register}
|
||||
\subsubsection*{Passwort vergessen und zurücksetzen \scriptsize{(\ref{a:forgot}, \ref{a:resetpassword})}}
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-forgotAndResetPW}
|
||||
|
||||
\subsubsection{Subscriptions \Gls{api}}
|
||||
\subsubsection*{Abonnements hochladen \scriptsize{(\ref{a:uploadSubs})}}
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-uploadSubscriptions}
|
||||
|
||||
\subsubsection*{Abrufen aller Abonnements \scriptsize{(\ref{a:getSubs})}}
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getSubscriptions}
|
||||
|
||||
\subsubsection{Episode Actions \Gls{api}}
|
||||
\subsubsection*{Episode Actions hochladen \scriptsize{(\ref{a:uploadEpisodeActions})}}
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-uploadEpisodeActions}
|
||||
|
||||
\subsubsection*{Abrufen aller Episode Actions seit einem Zeitpunkt \scriptsize{(\ref{a:getEpisodeActions})}}
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince}
|
||||
|
||||
\subsubsection*{Abrufen aller Episode Actions \scriptsize{(\ref{a:getEpisodeActions})}}
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getEpisodeActions}
|
||||
|
||||
\subsection{Komponentendiagramm Backend}
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/backendComponentDiagram}
|
||||
|
||||
\subsection{Verteilungsdiagram}
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/deployment}
|
||||
|
||||
\subsection{\Gls{db}-Modell}
|
||||
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/db}
|
||||
|
28
10-entwurfsheft/sections/backend.tex
Normal file
|
@ -0,0 +1,28 @@
|
|||
\section{Backend}
|
||||
|
||||
Für das Backend wird das \Gls{java}-Framework \Gls{spring} verwendet. Neben seiner Modularität,
|
||||
bietet es viele Funktionen, die unter
|
||||
anderem die Entwicklung von Backend-Anwendungen vereinfachen.
|
||||
Darunter fällt zum Beispiel die Unterstützung von Dependency Injection, dessen
|
||||
Vorteile bereits beschrieben wurden.
|
||||
Außerdem unterstützt \Gls{java} \Gls{spring} intern eine Verwaltung von \Glspl{db}, sodass
|
||||
sich nicht mit dem \Gls{SQL}-Code an sich befasst werden muss.
|
||||
Auch bezüglich Authentifizierung und Sicherheit bietet \Gls{spring} eigene Funktionalitäten.
|
||||
|
||||
Zusätzlich dazu wird als Build-System für das \Gls{java}-\Gls{spring}-Backend Maven verwendet.
|
||||
Maven hilft dabei alle Abhängigkeiten des Projekts zu verwalten und automatisiert
|
||||
den Build Prozess.
|
||||
Durch die zusätzliche Unterstützung von Versionskontrollsystemen und der Kompatibilität
|
||||
zu vielen Continuous Integration-Tools wird außerdem die Entwicklung in einem Team erleichtert
|
||||
und optimiert. Denn dadurch können Build- und Deployment-Prozesse automatisiert werden.
|
||||
Außerdem bietet Maven Bibliotheken zum Testen sowie zur Generierung von Dokumentationen an.
|
||||
|
||||
Vom Backend benötigte Abhängigkeiten:
|
||||
\begin{itemize}
|
||||
\item \Gls{spring} Web
|
||||
\item \Gls{spring} Security
|
||||
\item \Gls{spring} Mail Sender
|
||||
\item \Gls{spring} Data JPA
|
||||
\item Lombok
|
||||
\item Rome (\Gls{rss} parsing/fetching)
|
||||
\end{itemize}
|
41
10-entwurfsheft/sections/changes.tex
Normal file
|
@ -0,0 +1,41 @@
|
|||
|
||||
\section{Änderungen zum Pflichtenheft}
|
||||
|
||||
Im Folgenden werden die Änderungen zum Pflichtenheft aufgelistet.
|
||||
Hierbei handelt es sich um neue Kriterien, Kriterien die wegfallen und Kriterien die modifiziert wurden.
|
||||
|
||||
\subsection{Neue Kriterien}
|
||||
|
||||
\subsubsection{Cooldown Fetch-Vorgang}
|
||||
\begin{description}
|
||||
\item[\textcolor{Green}{\textlangle RS11\textrangle}] \textcolor{Green}{Wenn ein Nuter ein \Gls{abo} oder eine \Gls{episode} eines \Gls{abo} hinzugefügt hat, welche noch nicht
|
||||
in der \Gls{db} vorhanden ist, werden die Daten vom entsprechenden Server gefetched. Bis eine weitere fetch-Anfrage
|
||||
zum selben \Gls{abo} gestartet wird, wird ein Cooldown von einer Stunde abgewartet.
|
||||
Das hilft dabei DoS Angriffe zu vermeiden, da der Server damit nicht durch zu viele Fetch-Anfragen überlastet
|
||||
werden kann.}
|
||||
\end{description}
|
||||
|
||||
\subsubsection{Sprache von Browserinformationen übernehmen}
|
||||
\begin{description}
|
||||
\item[\textcolor{Green}{\textlangle RC13\textrangle}] \textcolor{Green}{Betritt ein Nutzer zum ersten Mal die Webseite, ruft ein Skript die Browserdaten zur eingestellten Sprache ab.
|
||||
Die Sprache wird im localStorage gespeichert und ruft entsprechend die Webseite in der jeweiligen Sprache auf.
|
||||
Ändert der Nutzer die Sprache, so wird dies durch eine Änderung der Sprachvariable im localStorage festgehalten. }
|
||||
\end{description}
|
||||
|
||||
\subsection{Abgeänderte Kriterien}
|
||||
|
||||
\subsubsection{Sessionspeicherung mit JWT}
|
||||
|
||||
\begin{description}
|
||||
\item[\textlangle RS10\textrangle] Im Webfrontend angemeldete Benutzer bleiben dort angemeldet.
|
||||
Hierfür wird ein \Gls{session-token} in einem \Gls{cookie} gespeichert.
|
||||
\textcolor{blue}{Als \Gls{session-token} wird ein \Gls{json} Web Token verwendet.
|
||||
Dieser Token wird für die Authentifikation genutzt.}
|
||||
\end{description}
|
||||
|
||||
\subsection{Entfernte Kriterien}
|
||||
|
||||
\begin{description}
|
||||
\item[\textlangle RC5\textrangle]
|
||||
\textcolor{red}{\sout{Die Weboberfläche ist kompatibel mit beliebigen \Glspl{gpodder}.}}
|
||||
\end{description}
|
22
10-entwurfsheft/sections/einleitung.tex
Normal file
|
@ -0,0 +1,22 @@
|
|||
\section{Einleitung}
|
||||
|
||||
Im vorangegangenen Pflichtenheft wurde ein Synchronisationsserver für \Glspl{podcast} beschrieben.
|
||||
In diesem Entwurfsheft wird die Implementierung dieses Synchronisationsservers
|
||||
mithilfe eines Entwurfes geplant.
|
||||
Wie im Pflichtenheft beschrieben, wird das finale Produkt
|
||||
aus einem Backend und einem Frontend bestehen.
|
||||
|
||||
Das Webfrontend dient dazu, dem Nutzer eine Oberfläche zur Accountverwaltung
|
||||
und Einsicht seiner Synchronisationsstände und Daten zu ermöglichen.
|
||||
Dieses wird mithilfe des Javascript Frameworks Vue.js erstellt.
|
||||
|
||||
Das Backend dient dazu, HTTP-Anfragen des Frontends und der \Gls{podcatcher} entgegenzunehmen,
|
||||
zu verarbeiten sowie zu beantworten.
|
||||
Damit Daten persistent gespeichert werden können, wird eine \Gls{db} eingebunden.
|
||||
Zur Erstellung des Backends wird \Gls{java} \Gls{spring} verwendet und für die \Gls{db} MariaDB.
|
||||
|
||||
%Neben den Schichten gibt es drei große Zuordnungsbereiche in unserem Produkt.
|
||||
%Nämlich die Abonnements die ein Nutzer haben kann, deren Episoden
|
||||
%und die Accountverwaltung.
|
||||
%Deshalb unterteilen wir die einzelnen Projektklassen
|
||||
%schichtenübergreifend gemäß dieser Kategorien nochmals in einzelne Pakete.
|
150
10-entwurfsheft/sections/frontend.tex
Normal file
|
@ -0,0 +1,150 @@
|
|||
\section{Weboberfläche}
|
||||
|
||||
Die Weboberfläche wird mit dem Frontend-Web-Framework Vue.js erstellt. Mit Vue
|
||||
werden wiederverwendbare, auf Datenänderungen reagierende Komponenten erstellt.
|
||||
Die Komponenten nutzen ein fertiges Aussehen von dem Frontend-CSS-Framework
|
||||
Bootstrap. Außerdem werden Icons der freien Schriftart fontawesome
|
||||
verwendet.
|
||||
|
||||
Das Projekt wird durch den \Gls{bundler} vite aufgesetzt, gebaut und stellt einen
|
||||
Entwicklungswebserver mit Echtzeitvorschau bereit. Durch den vue-router wird bei
|
||||
der \Gls{spa} ein Seitenwechsel durch Manipulation der
|
||||
Browser-Chronik (History Manipulation) simuliert. Dadurch hat der Nutzer eine
|
||||
bessere Erfahrung, weil die Seite nicht neu geladen werden muss, wenn zu einem
|
||||
anderen Menüpunkt gewechselt wird.
|
||||
|
||||
Wenn der Nutzer sich anmeldet wird die E-Mail-Adresse, der \Gls{session-token} und
|
||||
Spracheinstellungen in dem globallen Zustandsspeicher gespeichert, welcher durch
|
||||
die Pinia-Abhängigkeit bereitgestellt wird. Dadurch haben alle
|
||||
\Glspl{uiComponent} einfachen Zugriff auf die Daten und diese müssen nicht über
|
||||
Props in tiefliegende \Glspl{uiComponent} durchgereicht werden.
|
||||
|
||||
Die Seiten werden als einzelne Kompontenten erstellt. Andere HTML-Strukturen
|
||||
werden als eigene Komponenten ausgelagert, wenn sie in mehreren Seiten verwendet
|
||||
werden und zur Reduzierung von Komplexität und Duplikation beitragen und selbst
|
||||
Logik beinhalten.
|
||||
|
||||
Vom Frontend benötigte Abhängigkeiten:
|
||||
\begin{itemize}
|
||||
\item vite
|
||||
\item vue
|
||||
\item vue-router
|
||||
\item Pinia (globaler Zustandsspeicher)
|
||||
\item bootstrap
|
||||
\item fontawesome
|
||||
\item vue-i18n (Support für mehrere Sprachen)
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Komponentendiagramm Web-Frontend}
|
||||
\includegraphics[width=\textwidth]{assets/diagrams/componentdiagram}
|
||||
|
||||
\subsection{Komponentenbeschreibung}
|
||||
|
||||
\begin{minipage}{.7\linewidth}
|
||||
|
||||
\subsubsection*{SubscriptionComponent}
|
||||
|
||||
\begin{description}
|
||||
\item[Tag] \texttt{<Subscription subscription>}
|
||||
\item[Props] \mbox{} \\
|
||||
\emph{subscription} \mbox{} Subscription-Objekt, welches Attribute zu einem \Gls{podcast} und
|
||||
dessen \Glspl{episode} enthält.
|
||||
\item[Beschreibung] Nimmt ein Subscription-Objekt, zeigt Titel und LastUpdate und
|
||||
\Glspl{episode} der Subscription an.
|
||||
\end{description}
|
||||
\end{minipage}
|
||||
\begin{minipage}{.3\linewidth}
|
||||
\begin{figure}[H]
|
||||
\includegraphics[width=\textwidth]{assets/subscription.png}
|
||||
\end{figure}
|
||||
\end{minipage}
|
||||
|
||||
|
||||
\vspace{.5cm}
|
||||
\begin{minipage}{.7\linewidth}
|
||||
\subsubsection*{EpisodeComponent}
|
||||
|
||||
\begin{description}
|
||||
\item[Tag] \texttt{<Episode episode>}
|
||||
\item[Props] \mbox{} \\
|
||||
\emph{episode} \mbox{} EpisodeAction-Objekt, welches Titel, \Gls{podcast},
|
||||
Timestamp, Dauer und Hörfortschritt der \Gls{episode} enthält.
|
||||
\item[Beschreibung] Nimmt ein EpisodeAction-Object, zeigt Titel, \Gls{podcast}, Dauer,
|
||||
Hörfortschritt und LastUpdate an.
|
||||
\end{description}
|
||||
\end{minipage}
|
||||
\begin{minipage}{.3\linewidth}
|
||||
\begin{figure}[H]
|
||||
\includegraphics[width=\textwidth]{assets/episode.png}
|
||||
\end{figure}
|
||||
\end{minipage}
|
||||
|
||||
|
||||
\vspace{.5cm}
|
||||
\begin{minipage}{.7\linewidth}
|
||||
\subsubsection*{LastUpdateComponent}
|
||||
|
||||
\begin{description}
|
||||
\item[Tag] \texttt{<LastUpdate timestamp>}
|
||||
\item[Props] \mbox{} \\
|
||||
\emph{timestamp} \mbox{} Date-Objekt, welches die Zeit der letzten Änderung enthält
|
||||
\item[Beschreibung] Nimmt ein Timestamp und gibt die Zeit seit dem Timestamp in
|
||||
einem menschenlesbaren Format aus.
|
||||
\end{description}
|
||||
\end{minipage}
|
||||
\begin{minipage}{.3\linewidth}
|
||||
\begin{figure}[H]
|
||||
\includegraphics[width=\textwidth]{assets/lastupdate.png}
|
||||
\end{figure}
|
||||
\end{minipage}
|
||||
|
||||
|
||||
\vspace{.5cm}
|
||||
\begin{minipage}{.7\linewidth}
|
||||
\subsubsection*{HelpComponent}
|
||||
|
||||
\begin{description}
|
||||
\item[Tag] \texttt{<Help>}
|
||||
\item[Beschreibung] Zeigt Hilfestellungen in einem Fenster an. Dieses kann über
|
||||
die Navigationsleiste aufgerufen werden.
|
||||
\end{description}
|
||||
\end{minipage}
|
||||
\begin{minipage}{.3\linewidth}
|
||||
\begin{figure}[H]
|
||||
\includegraphics[width=\textwidth]{assets/help.png}
|
||||
\end{figure}
|
||||
\end{minipage}
|
||||
|
||||
|
||||
\vspace{.5cm}
|
||||
\begin{minipage}{.7\linewidth}
|
||||
\subsubsection*{NavbarComponent}
|
||||
|
||||
\begin{description}
|
||||
\item[Tag] \texttt{<Navbar>}
|
||||
\item[Beschreibung] Enthält route-links zu im vue-router definierten Pfaden.
|
||||
\end{description}
|
||||
\end{minipage}
|
||||
\begin{minipage}{.3\linewidth}
|
||||
\begin{figure}[H]
|
||||
\fbox{\includegraphics[width=\textwidth]{assets/navbar.png}}
|
||||
\end{figure}
|
||||
\end{minipage}
|
||||
|
||||
|
||||
\vspace{.5cm}
|
||||
\begin{minipage}{.7\linewidth}
|
||||
\subsubsection*{PasswordValidatorComponent}
|
||||
|
||||
\begin{description}
|
||||
\item[Tag] \texttt{<Password>}
|
||||
\item[Beschreibung] Überprüft ob der eingegebene Text die Bedingungen für ein
|
||||
sicheres Passwort erfüllt.
|
||||
\end{description}
|
||||
\end{minipage}
|
||||
\begin{minipage}{.3\linewidth}
|
||||
\begin{figure}[H]
|
||||
\includegraphics[width=\textwidth]{assets/password-margin.png}
|
||||
\end{figure}
|
||||
\end{minipage}
|
||||
|
371
10-entwurfsheft/sections/glossar.tex
Normal file
|
@ -0,0 +1,371 @@
|
|||
\makeglossaries
|
||||
|
||||
\newglossaryentry{spa}
|
||||
{
|
||||
name=Single-Page-Application,
|
||||
description={
|
||||
ist ein Webseiten-Modell, bei welchem dem Nutzer nur ein Webdokument
|
||||
bereitgestellt wird. Mit einem Skript wird der Inhalt der Seite
|
||||
dynamisch mit Daten einer API befüllt. Außerdem verwaltet die Seite
|
||||
(nicht der Server), welcher Inhalt bei welchem Pfad angezeigt wird. Dies
|
||||
erzeugt geringere Serverlast und eine bessere Nutzererfahrung, da die
|
||||
Seitenstruktur beim Laden von neuen Inhalten erhalten bleibt}
|
||||
}
|
||||
|
||||
\newglossaryentry{packagemanager}
|
||||
{
|
||||
name=Paketmanager,
|
||||
description={
|
||||
ist ein Programm, welches Pakete und dessen Abhängigkeiten verwaltet,
|
||||
installiert, entfernt und aktualisiert. Pakete können andere Programme,
|
||||
Plugins oder Software-Bibliotheken sein}
|
||||
}
|
||||
|
||||
\newglossaryentry{bundler}
|
||||
{
|
||||
name=Bundler,
|
||||
description={
|
||||
ist ein Programm, welches genutzte Teile von Abhängigkeiten eines
|
||||
Software-Projekts in passender Reihenfolge zusammensucht und daraus
|
||||
Dateien erstellt, die für den Nutzer bereitgestellt werden können. Dabei
|
||||
kann der Bundler mit zusätzlichen Modulen Dateien erzeugen, die
|
||||
rückwärtskompatibel oder für den Nutzer schwerer einsehbar sind}
|
||||
}
|
||||
|
||||
\newglossaryentry{java}
|
||||
{
|
||||
name=Java,
|
||||
description={
|
||||
ist eine objekt-orientierte interpretierte kompilierte
|
||||
Programmiersprache, welche plattformunabhängig auf einer virtuellen
|
||||
Maschine ausgeführt wird}
|
||||
}
|
||||
|
||||
\newglossaryentry{db}
|
||||
{
|
||||
name=Datenbank,
|
||||
plural=Datenbanken,
|
||||
description={
|
||||
ist ein System um Daten persistent zu speichern und effizient zu
|
||||
verwalten. Am meisten verbreitet sind relationale Datenbanken, welche
|
||||
Daten in Tabellen mit Referenzen zu Einträgen anderer Tabellen
|
||||
speichern. Programme können dann über eine Anfragesprache (Structured
|
||||
Query Language - \Gls{SQL}) komplexe Operationen auf den Daten ausführen}
|
||||
}
|
||||
|
||||
\newglossaryentry{docker}
|
||||
{
|
||||
name=Docker,
|
||||
description={
|
||||
ist ein Programm, das virtualisierte Container ausführt. Ein Programm in
|
||||
so einem Container läuft in seiner eigenen virtuellen Umgebung, wodurch
|
||||
das Host-System sicher bleibt. Zudem lassen sich die Container leicht
|
||||
auf andere Systeme verteilen}
|
||||
}
|
||||
|
||||
% RESTfull-API, JSON, RSS-Feed, Salting and Hasing, OAuth, Cookie, Garbage
|
||||
% Collection, DSGVO, Podcast, Podcatcher, Episode, Gpodder,
|
||||
|
||||
\newglossaryentry{podcatcher}
|
||||
{
|
||||
name=Podcatcher,
|
||||
plural=Podcatchern,
|
||||
description={
|
||||
ist ein Programm, über welches man Podcasts entdecken, abonnieren und
|
||||
Episoden von Podcasts hören kann. Mit einem Account auf einer Plattform,
|
||||
welche eine Gpodder-API zur Verfügung stellt, können Ereignisse, die von
|
||||
einem Nutzer ausgehen, auf anderen Podcatchern des Nutzers
|
||||
synchronisiert werden}
|
||||
}
|
||||
|
||||
\newglossaryentry{podcast}
|
||||
{
|
||||
name=Podcast,
|
||||
description={
|
||||
ist ein RSS-Feed, dessen Einträge die Episoden darstellen}
|
||||
}
|
||||
|
||||
\newglossaryentry{episode}
|
||||
{
|
||||
name=Episode,
|
||||
plural=Episoden,
|
||||
description={
|
||||
ist ein Eintrag in einem Podcast. Eine URL in dem Eintrag zeigt auf eine
|
||||
Medien-Datei, welche vom Podcatcher abgespielt werden kann}
|
||||
}
|
||||
|
||||
\newglossaryentry{rest-api}
|
||||
{
|
||||
name=RESTful-API,
|
||||
description={
|
||||
ist ein Schnittstellenentwurf über das Hypertext Transfer Protocol
|
||||
(HTTP), bei dem die Schnittstellen strukturiert als Pfad an einem
|
||||
Endpunkt erreichbar sind. Mittels verschiedener HTTP-Methoden können an
|
||||
der Schnittstelle Daten abgefragt (GET), gesendet (PUT), gelöscht
|
||||
(DELETE) oder geändert (POST) werden. Die Daten, die über die
|
||||
Schnittstelle gesendet werden liegen meist im JSON-Format vor}
|
||||
}
|
||||
|
||||
|
||||
\newglossaryentry{gpodder}
|
||||
{
|
||||
name=Gpodder-API,
|
||||
description={
|
||||
wird von gpodder.net benutzt und entwickelt. Die API wird als
|
||||
Schnittstelle zwischen Podcatchern und Podcast Synchronisationsservern
|
||||
verwendet. Weitere Details sind unter
|
||||
"https://gpoddernet.readthedocs.io/en/latest/api/" zu finden}
|
||||
}
|
||||
|
||||
\newglossaryentry{json}
|
||||
{
|
||||
name=JSON,
|
||||
description={
|
||||
(JavaScript Object Notation) ist ein Datenformat und wird zur
|
||||
Übertragung von Strukturen und Daten eingesetzt. JSON besteht dabei aus
|
||||
grundlegenden Datentypen sowie Objekten mit Schlüssel-Wert Paaren und
|
||||
Listen}
|
||||
}
|
||||
|
||||
\newglossaryentry{oauth}
|
||||
{
|
||||
name=OAuth,
|
||||
description={
|
||||
(Open Authorization) ist ein offenes Protokoll, welches es Nutzern
|
||||
ermöglicht, sich mit bereits bestehenden Accounts bei anderen Diensten
|
||||
zu registrieren. Dabei werden benötigte Daten für die Registrierung über
|
||||
die bereitgestellte Schnittstelle zur Verfügung gestellt}
|
||||
}
|
||||
|
||||
\newglossaryentry{garbage-collection}
|
||||
{
|
||||
name=Garbage Collection,
|
||||
description={
|
||||
ist eine automatische Speicherbereinigung, welche nicht mehr benötigten
|
||||
Speicherplatz wieder freigibt. Die Bereinigung kann dabei in determinierten
|
||||
Zeitintervallen erfolgen oder durch bestimmte Ereignisse ausgelöst
|
||||
werden}
|
||||
}
|
||||
|
||||
\newglossaryentry{salt-hash}
|
||||
{
|
||||
name=Salting und Hashing,
|
||||
description={
|
||||
ist eine Methode um Passwörter so zu kodieren, dass sie nicht als
|
||||
Klartext gespeichert werden und auch sicher vor Hash-Wörterbüchern sind.
|
||||
Dafür wird dem Passwort ein bekanntes Wort, der Salt, angefügt, bevor
|
||||
aus dem kompletten Wort eine Prüfsumme, ein Hash, generiert wird. Beim
|
||||
Anmelden wird die Prüfsumme der Anmeldung mit der bekannten
|
||||
Prüfsumme des Passworts verglichen}
|
||||
}
|
||||
|
||||
\newglossaryentry{rss}
|
||||
{
|
||||
name=RSS,
|
||||
description={
|
||||
(Really Simple Syndication) zeigt strukturiert Listen von Nachrichten
|
||||
an. Die Änderungen werden im XML-Format in sogenannte RSS-Dateien
|
||||
geschrieben, welche über einen Link abgerufen werden können}
|
||||
}
|
||||
|
||||
\newglossaryentry{dsgvo}
|
||||
{
|
||||
name=Datenschutz-Grundverordnung,
|
||||
description={
|
||||
(DSGVO) ist eine im europäischen Wirtschaftsraum
|
||||
geltende Verordnung. Sie sorgt für eine Reglementierung bei der
|
||||
Verarbeitung personenbezogener Daten. Unter anderem muss einsehbar sein,
|
||||
welche Daten von Nutzern erhoben werden. Außerdem muss für einen Nutzer
|
||||
die Möglichkeit bestehen, seine erhobenen Daten abrufen zu können}
|
||||
}
|
||||
|
||||
\newglossaryentry{push-pull}
|
||||
{
|
||||
name=Push und Pull,
|
||||
description={
|
||||
sind Methoden, um Daten auszutauschen. Bei der Pull-Methode
|
||||
stellt Akteur A einem Akteur B eine Anfrage auf Daten und erhält diese
|
||||
als Antwort. Damit Akteur A und B immer auf dem selben Stand sind, muss
|
||||
Akteur A chronisch Anfragen an Akteur B stellen. Im Gegensatz dazu steht
|
||||
die Push-Methode, bei der Akteur B den Akteuren mitteilt, dass er neue
|
||||
Änderungen hat. Dafür muss Akteur B allerdings wissen mit welchen
|
||||
anderen Akteuren er in Verbindung steht und diese Verbindung aufrecht
|
||||
erhalten}
|
||||
}
|
||||
|
||||
\newglossaryentry{ui-lib}
|
||||
{
|
||||
name=UI-Bibliothek,
|
||||
plural=UI-Bibliotheken,
|
||||
description={
|
||||
kümmert sich um das Layout einer Webseite. Dabei unterscheidet man
|
||||
zwischen Design-Bibliotheken (wie Bootstrap), welche fertige
|
||||
UI-Komponenten bereitstellen, und Layout-Bibliotheken (wie Vue oder
|
||||
React.js), welche die Komponenten basierend auf Daten dynamisch
|
||||
anzeigen}
|
||||
}
|
||||
|
||||
\newglossaryentry{responsive}
|
||||
{
|
||||
name=Responsive,
|
||||
description={
|
||||
Design ist ein Design-Prinzip für Webseiten, bei dem die selbe Webseite ihre
|
||||
Komponenten dynamisch der Bildschirmbreite anpasst}
|
||||
}
|
||||
|
||||
\newglossaryentry{pseudoprotocol}
|
||||
{
|
||||
name=Pseudoprotokoll,
|
||||
description={
|
||||
ist ein URL-Schema, auf das Webseiten hören können, wenn sie sich das
|
||||
URL-Schema im Browser anmelden. Bekannt Pseudoprotokolle sind:
|
||||
,,mailto:'', ,,tel:'' oder ,,irc:''}
|
||||
}
|
||||
|
||||
\newglossaryentry{dashboard}
|
||||
{
|
||||
name=Dashboard,
|
||||
description={
|
||||
ist die erste Seite auf der man landet, wenn man angemeldet ist}
|
||||
}
|
||||
|
||||
\newglossaryentry{abo}
|
||||
{
|
||||
name=Abonnement,
|
||||
description={
|
||||
ist ein abonnierter Podcast}
|
||||
}
|
||||
|
||||
\newglossaryentry{discovery}
|
||||
{
|
||||
name=Discovery,
|
||||
description={
|
||||
ist ein Feature der Gpodder-API, welches dem Nutzer eine Reihe von
|
||||
Podcasts zum abonnieren anbietet}
|
||||
}
|
||||
|
||||
\newglossaryentry{session-token}
|
||||
{
|
||||
name=Session-Token,
|
||||
description={
|
||||
ist ein Wort, dass vom Client gespeichert wird solange der Nutzer
|
||||
eingeloggt ist und bei jeder Anfrage an den Server mitgeschickt wird.
|
||||
Der Server kann den Session-Token einem Nutzer zuordnen und so mit
|
||||
nutzerspezifischen Daten antworten}
|
||||
}
|
||||
|
||||
\newglossaryentry{cookie}
|
||||
{
|
||||
name=Cookie,
|
||||
description={
|
||||
ist ein kleiner webseitenspezifischer Speicher im Browser, welcher vom
|
||||
Server und von der Webseite gesetzt werden kann und bei jeder weiteren
|
||||
Anfrage an den Server mitgesendet wird. Cookies bleiben entweder
|
||||
temporär im Browserspeicher, bis der Browser geschlossen wird oder
|
||||
permanent, bis ein optionales Verfallsdatum erreicht ist}
|
||||
}
|
||||
|
||||
\newglossaryentry{uiComponent}
|
||||
{
|
||||
name=UI-Komponente,
|
||||
plural=UI-Komponenten,
|
||||
description={
|
||||
In Vue.js werden die grafischen Elemente einer Webseite in einzelne
|
||||
Komponenten zerteilt.
|
||||
Diese reagieren automatisch auf Änderungen und können ohne Neuladen
|
||||
der Seite ihr Aussehen verändern und somit Änderungen direkt anzeigen}
|
||||
}
|
||||
|
||||
\newglossaryentry{spring}
|
||||
{
|
||||
name=Spring,
|
||||
description={
|
||||
Ein Java-Framework, welches die Entwicklung von Web-Applikationen erleichtert.
|
||||
Dazu wird eine Reihe von Werkzeugsets zur Verfügung gestellt.
|
||||
Unter anderem sind das Spring Web für das Erstellen von Webanwendungen,
|
||||
Spring Security für die Verwaltung von Benutzerauthentifizierungen und
|
||||
Spring Data JPA für die Arbeit mit relationalen Datenbanken
|
||||
}
|
||||
}
|
||||
|
||||
\newglossaryentry{api}
|
||||
{
|
||||
name=API,
|
||||
plural=APIs,
|
||||
description={
|
||||
Eine Schnittstelle, welche es ermöglicht auf Funktionalitäten einer Anwendung
|
||||
zuzugreifen. APIs für Webanwendungen heißen WebAPIs.
|
||||
Ein Beispiel für eine WebAPI ist die REST-API
|
||||
}
|
||||
}
|
||||
|
||||
\newglossaryentry{business}
|
||||
{
|
||||
name=Geschäftslogik,
|
||||
description={
|
||||
Eine Schicht in der Anwendungsentwicklung, in der die Art und Weise, wie das
|
||||
Programm auf Eingaben reagiert, wie Daten verarbeitet und wie sie gespeichert
|
||||
werden sollen, festgelegt ist
|
||||
}
|
||||
}
|
||||
|
||||
\newglossaryentry{solid}
|
||||
{
|
||||
name=SOLID,
|
||||
description={
|
||||
Eine Sammlung an Prinzipien, welche zu gutem objektorientierten Design führen soll.
|
||||
Jedes Prinzip steht für einen Buchstaben in SOLID:
|
||||
\textbf{S}ingle-Responsibility Prinzip,
|
||||
\textbf{O}pen-Closed Prinzip,
|
||||
\textbf{L}iskovsches Substitutionsprinzip,
|
||||
\textbf{I}nterface Segregation Prinzip und
|
||||
\textbf{D}ependency Inversion Prinzip
|
||||
}
|
||||
}
|
||||
|
||||
\newglossaryentry{crud}
|
||||
{
|
||||
name=CRUD,
|
||||
description={
|
||||
CRUD steht für \textbf{C}reate, \textbf{R}ead, \textbf{U}pdate und \textbf{D}elete.
|
||||
Hierbei handelt es sich um die grundlegenden Funktionen einer Anwendung,
|
||||
die mit einer Datenbank arbeitet.
|
||||
Hierbei können Daten angelegt, abgerufen, aktualisiert und gelöscht werden.
|
||||
Auch in Web-Applikationen ist CRUD mit HTTP über die Anfragen POST, GET, PUT und DELETE
|
||||
vertreten
|
||||
}
|
||||
}
|
||||
|
||||
\newglossaryentry{SQL}
|
||||
{
|
||||
name=SQL,
|
||||
description={
|
||||
SQL (Structured Query Language) ist eine Sprache, die einen strukturierten Zugriff auf Datenbanken ermöglicht.
|
||||
Daten können hierbei hinzugefügt, abgefragt, geändert und gelöscht werden.
|
||||
Das besondere hierbei ist der strukturierte Zugriff auf Daten, indem explizit Daten mit bestimmten Kriterien und
|
||||
Relationen ausgewählt und bearbeitet werden können.
|
||||
SQL wird fast von allen verbreiteten Datenbanksystemen unterstützt
|
||||
}
|
||||
}
|
||||
|
||||
\newglossaryentry{Base64}
|
||||
{
|
||||
name=Base64,
|
||||
description={
|
||||
Mithilfe von Base64 können 8-Bit-Binärdaten in eine ASCII-Zeichenkette
|
||||
kodiert werden. So werden zum Beispiel E-Mail-Anhänge versendet
|
||||
}
|
||||
}
|
||||
|
||||
\newglossaryentry{JSONP}
|
||||
{
|
||||
name=JSONP,
|
||||
description={
|
||||
JSONP ermöglicht die Übertragung von JSON-Daten zwischen verschiedenen Domains.
|
||||
Dies wäre durch die Same-Origin-Policy nicht möglich.
|
||||
JSONP nutzt allerdings die Tatsache aus,
|
||||
dass sich Skripte domainübergreifend übertragen lassen.
|
||||
Dazu werden die JSON-Daten als Argument einer übergebenen Funktion über
|
||||
ein Skript-Element eingebunden
|
||||
}
|
||||
}
|
104
10-entwurfsheft/sections/structure.tex
Normal file
|
@ -0,0 +1,104 @@
|
|||
\section{Entwurfsmuster und Techniken}
|
||||
|
||||
\subsection{Entwurfsmuster}
|
||||
|
||||
\subsubsection{Dependency Injection}
|
||||
|
||||
Die Dependency Injection (dt. Abhängigkeitsinjektion) ist ein Entwurfsmuster, welches die Abhängigkeiten von Objekten bestimmt und an einem zentralen Ort speichert sowie verwaltet.
|
||||
Sollte ein Objekt also von einem anderen Objekt abhängig sein, so wird an diesem zentralen Ort nach der Abhängigkeit gesucht.
|
||||
Ist die Abhängigkeit vorhanden, so wird dieses Objekt dann an dem benötigten Ort eingesetzt (injiziert).
|
||||
Dies geschieht während der Laufzeit.
|
||||
Der zentrale Ort, an dem die Abhängigkeiten gespeichert werden, wird meist von einem Framework verwaltet.
|
||||
|
||||
Im Falle dieses Projekts ist \Gls{spring} das Framework und der \Gls{spring} Container der zentrale Ort, an dem die Abhängigkeiten gespeichert werden.
|
||||
Der Vorteil dieses Entwurfsmusters ist, dass Objekte von anderen Objekten abgekoppelt werden, sprich: Das Objekt mit der Abhängigkeit muss nicht mehr von der expliziten Klasse Kenntnis haben und es kann nur mit Interfaces gearbeitet werden, was in den \Gls{solid}-Kriterien das D für Dependency Inversion erfüllt.
|
||||
Ein weiterer Vorteil ist, dass die Abhängigkeiten innerhalb einer Konfigurationsdatei definiert werden können.
|
||||
Sprich: Man kann mehrere Implementierungen besitzen, die alle das gleiche Interface implementieren und kann in der Konfigurationsdatei angeben, welche Implementierung gewählt werden soll.
|
||||
|
||||
\subsubsection{Data Access Object (DAO)}
|
||||
\label{DAO_Pattern}
|
||||
|
||||
Das Data Access Object (kurz: DAO, dt: Datenzugriffsobjekt) ist ein Entwurfsmuster, das eingesetzt wird um den Zugriff auf \Gls{db}en zu vereinfachen und die \Gls{business} von der Datenzugriffslogik zu trennen.
|
||||
Dazu gibt es zwei Komponenten: das DAO-Interface und die DAO-Implementierung.
|
||||
|
||||
Das DAO-Interface wird von allen DAO-Implementierungen implementiert und bietet alle Datenzugriffsfunktionen an, auf die die \Gls{business} zugreift.
|
||||
Die DAO-Implementierung ist eine Klasse, die das DAO-Interface implementiert und den tatsächlichen Zugriff auf die \Gls{db} ausführt.
|
||||
|
||||
Der Vorteil dieses Entwurfsmusters ist es mehrere Implementierungen desselben DAO-Interfaces zu besitzen.
|
||||
In Kombination mit der Dependency Injection ist es einfach zwischen den Implementierungen für verschiedene \Gls{db}en (bspw. MariaDB und My\Gls{SQL}) zu wechseln.
|
||||
Damit wird der Datenzugriff flexibler.
|
||||
Im Falle dieses Projekts wird eine DAO-Implementierung für MariaDB verwendet.
|
||||
|
||||
Ein weiterer Vorteil ist die zuvor angesprochene Trennung der Geschäfts- und Datenzugriffslogik.
|
||||
Da sich die \Gls{business} und Datenzugriffslogik mithilfe dieses Musters in verschiedenen Komponenten befinden, sind diese voneinander getrennt und es wird einfacher die jeweiligen Implementierungen zu testen.
|
||||
Gleichzeitig verbessert sich damit die Wiederverwendbarkeit des Codes, da die DAO-Implementierungen in anderen Programmen, die mit demselben DAO-Interface arbeiten, eingesetzt werden können.
|
||||
|
||||
Damit erfüllt das DAO-Muster die Kriterien S und O der \Gls{solid}-Kriterien.
|
||||
Das Single-Responsibility Prinzip wird erfüllt, da der Zugriff auf die \Gls{db} von der \Gls{business} getrennt wird und damit die DAO-Implementierung alleine für den Zugriff auf die \Gls{db} verantwortlich ist.
|
||||
Das Open/Closed Prinzip wird erfüllt, da die DAO-Implementierung erweitert werden kann, ohne dass der Rest vom Projekt betroffen wird und außerhalb der Klasse nur mit dem DAO-Interface gearbeitet werden kann.
|
||||
|
||||
\subsection{Techniken}
|
||||
|
||||
\subsubsection{JSON Web Token}
|
||||
|
||||
\Gls{json} Web Token (JWT) ist ein offener Standard der in RFC 7519 definiert wird.
|
||||
Mit einem JWT ist es möglich Informationen sicher in einem kodierten \Gls{json} Objekt zu übertragen.
|
||||
Die Sicherheit der Daten wird dabei durch eine digitale Signatur gewährleistet.
|
||||
|
||||
Ein JWT besteht aus drei durch Punkte ('.') voneinander getrennten Teilen:
|
||||
\texttt{Header}, \texttt{Payload} und \texttt{Signatur}.
|
||||
Der \texttt{Header} besteht dabei typischerweise aus der Information um welchen Typ von Token es sich handelt, also einen JWT,
|
||||
und der Information welcher Signierungs-Algorithmus verwendet wird.
|
||||
Diese Informationen werden \Gls{Base64} kodiert und bilden den ersten Teil des JWT.
|
||||
|
||||
Im \texttt{Payload} Teil werden die eigentlichen Informationen \Gls{Base64} kodiert.
|
||||
|
||||
Die \texttt{Signatur} ergibt sich durch die mit einem Punkt voneinander getrennten Kodierungen des \texttt{Headers} und
|
||||
des \texttt{Payload}-Teils. Diese Zeichenkette wird dann mit einem geheimen Schlüssel
|
||||
durch den im \texttt{Header} angegebenen Signierungs-Algorithmus signiert.
|
||||
JWT werden einmalig vom Server erzeugt und beim Client gehalten. Daher ist es
|
||||
nicht notwendig wie z.B. bei \gls{cookie} basierten Sessions, eine Liste mit gültigen Sessions auf dem Server zu verwalten, was bei mehreren Servern schwierig ist.
|
||||
|
||||
In diesem Projekt werden JWT zur Verifikation der E-Mail-Adresse eines Benutzers und zur Überprüfung der Autorisation bei Anfragen an den Server verwendet.
|
||||
|
||||
Zur Bestätigung der E-Mail-Adresse speichert der Server die zur Verifikation des
|
||||
Benutzers benötigten Daten in einem JWT. Dieser wird in der URL des Verifikations-Links kodiert. Wenn der Benutzer den Verifikations-Link anklickt,
|
||||
wird der JWT an den Server weitergeleitet. Dieser überprüft die Signatur des JWT ihn mit seinem geheimen Schlüssel
|
||||
und kann so die Verifikation der E-Mail-Adresse abschließen.
|
||||
|
||||
Bei dem Login-Vorgang sendet der Client zuerst seine Anmeldedaten (Benutername und Passwort), um sich zu authentifizieren.
|
||||
Der Server überprüft die Angaben, generiert einen JWT und gibt diesen zurück, falls die Daten korrekt sind.
|
||||
Bei späteren Anfragen an den Server übermittelt der Client diesen JWT. Der Server überprüft die Validität des JWT und trifft
|
||||
basierend darauf die Entscheidung, ob die Anfrage bearbeitet oder abgelehnt wird.
|
||||
|
||||
\subsubsection{Objektrelationale Abbildung (Object-relational mapping)}\label{t:orm}
|
||||
|
||||
Objektrelationale Abbildung - kurz ORM von der englischen Bezeichnung \enquote{Object-relational mapping} - ist eine Technik der Softwareentwicklung.
|
||||
Sie widmet sich dem, mit der persistenten Speicherung von Laufzeit-Objekten zusammenhängenden \enquote{Impedance mismatch} Problem.
|
||||
Dieses beschreibt die Diskrepanz zwischen den in der Pogrammier- beziehungsweise \Gls{db}welt vorherrschenden Konzepten - nämlich der objektorientierten Programmierung und relationalen \Gls{db}en.
|
||||
So speichern objektorientierte Programmiersprachen Daten und Verhalten in Objekten mit eindeutiger Identität, wobei Zustand und Verhalten hinter einer Schnittstelle verborgen werden.
|
||||
Relationale \Gls{db}en hingegen speichern Daten in Tabellen und basieren auf dem mathematischen Konzept der Relationenalgebra.
|
||||
|
||||
Objektrelationale Abbildung bietet eine Möglichkeit diese Diskrepanz zu vermindern, indem sie ein Mapping zwischen Objekten und Datenstrukturen relationaler \Gls{db}en herstellt.
|
||||
Einem, in einer objektorientierten Programmiersprache geschriebenen, Anwendungsprogramm erscheint dann die verbundene relationale \Gls{db} als objektorientierte \Gls{db}.
|
||||
Durch ORM wird also sowohl das Ablegen von Objekten mit Attributen und Methoden in relationale \Gls{db}en, als auch das Erzeugen von solchen Objekten aus entsprechenden Datensätzen ermöglicht.
|
||||
Vorteilhaft ist daran außerdem, dass die objektorientierte Programmiersprache nicht erweitert werden muss.
|
||||
Des Weiteren existiert für jede Umgebung ausgereifte Software für die Verwendung relationaler \Gls{db}en.
|
||||
Allerdings ist der Schritt in Richtung objektorientiertem Ansatz immanent ein Schritt weg von den eigentlichen Stärken relationaler \Gls{db}en.
|
||||
|
||||
Der grundlegende Ansatz ist die Abbildung von Klassen auf Tabellen, wobei die Spalten den Attributen und die Zeilen den Objekten der Klasse zugeordnet sind.
|
||||
Dabei entspricht der Primärschlüssel der Tabelle der Objektidentität und Objektreferenzen werden mithilfe von zusätzlichen Fremdschlüsseln repräsentiert.
|
||||
%Um Vererbung abzubilden gibt es drei grundlegende Möglichkeiten.
|
||||
%Erst einmal kann für eine Vererbungshierarchie auch genau eine gemeinsame Tabelle mit allen Attributen verwendet werden, in der ein Diskriminator bestimmt, zu welcher Klasse ein Objekt gehört.
|
||||
%Als zweite Option kann pro Unterklasse eine zusätzliche verknüpfte Tabelle eingeführt werden.
|
||||
%Letztlich kann auch pro konkreter Klasse eine Tabelle verwendet werden, wobei die Tabelle für die abstrakte Basisklasse entfällt.
|
||||
|
||||
Die von diesem Mapping betroffenen Klassen aus dem Model-Paket (\ref{p:model}) des Backends sind User, SubscriptionAction, Subscription, EpisodeAction und \Gls{episode}.
|
||||
|
||||
Konkret für dieses Projekt findet ORM als Technik durch die Implementierung der Jakarta Persistence \Gls{api} (JPA) Anwendung.
|
||||
Dafür wird das von \Gls{spring} zur Implementierung von JPA-basierten Datenzugriffsschichten bereitgestellte Modul \Gls{spring} Data JPA genutzt.
|
||||
Als JPA-Implementation wiederum wird das Open-Source-Persistenz- und ORM-Framework Hibernate für \Gls{java} verwendet.
|
||||
Dabei erfolgen Abfragen der persistierten Objekte über die Abfragesprache Jakarta Persistence Query Language (JPQL), welche dann mittels JDBC in den entsprechen \Gls{SQL}-Dialekt für MariaDB übersetzt.
|
||||
%Hier sei angemerkt, dass JPQL eine Untermenge der Hibernate Query Language (HQL) ist.
|
||||
|
||||
\newpage
|
5377
10-entwurfsheft/tikz-uml.sty
Normal file
75
10-entwurfsheft/titlepage.tex
Normal file
|
@ -0,0 +1,75 @@
|
|||
%% Encoding: UTF-8 %%
|
||||
|
||||
%% titlepage.tex
|
||||
|
||||
\def\usesf{}
|
||||
\let\usesf\sffamily % diese Zeile auskommentieren für normalen TeX Font
|
||||
|
||||
\begin{titlepage}
|
||||
|
||||
\setlength{\unitlength}{1pt}
|
||||
\begin{picture}(00,0)(70,770)
|
||||
\includegraphics[width=\paperwidth]{assets/KIT_Deckblatt.pdf}
|
||||
\end{picture}
|
||||
|
||||
\thispagestyle{empty}
|
||||
|
||||
\begin{center}
|
||||
\hbox{}
|
||||
\vfill
|
||||
\includegraphics[width=.5\textwidth]{assets/logo.pdf}
|
||||
\vskip 1cm
|
||||
{\usesf
|
||||
{\huge\bfseries PSE\textsuperscript{2} - Podcast Synchronisation \\
|
||||
made Efficient\\
|
||||
Entwurfsheft \par}
|
||||
\vskip 1.8cm
|
||||
{\Large Wintersemester 2022/2023\\}
|
||||
%von\\[2mm]
|
||||
\vskip 1.5cm
|
||||
|
||||
% {\large\bfseries Vorname Nachname\\}
|
||||
% \vskip 1.2cm
|
||||
Praxis der Softwareentwicklung \\
|
||||
Prof. Dr.-Ing. Gregor Snelting \\
|
||||
Fakultät für Informatik\\
|
||||
Karlsruher Institut für Technologie\\
|
||||
\vskip 1.5cm
|
||||
\begin{tabular}{p{20mm}l}
|
||||
Autoren:
|
||||
& Daniel Hönlinger \\
|
||||
& Gero Beckmann \\
|
||||
& Immanuel Reitz \\
|
||||
& Julius Friesen \\
|
||||
& Lukas Schmidheissler \\
|
||||
\\
|
||||
Betreuer: & M.Sc. Hans-Peter Lehmann \\
|
||||
& M.Sc. Daniel Seemaier
|
||||
\end{tabular}
|
||||
}
|
||||
\end{center}
|
||||
\vfill
|
||||
|
||||
%\begin{textblock}{10}[0,0](4,15)
|
||||
% \includegraphics[width=.3\textwidth]{logos/logo.pdf}
|
||||
%\end{textblock}
|
||||
|
||||
% \begin{textblock}{8}[0,0](14,14)
|
||||
% \includegraphics[width=.3\textwidth]{logos/KASTEL_logo.pdf}
|
||||
% \end{textblock}
|
||||
|
||||
\end{titlepage}
|
||||
|
||||
% \thispagestyle{empty}
|
||||
% \ \vfill
|
||||
% \begin{flushleft}
|
||||
% Copyright $\copyright$ ITI und Verfasser 201?\\
|
||||
% \ \\
|
||||
% Institut für Theoretische Informatik
|
||||
% Fakultät für Informatik\\
|
||||
% Karlsruher Institut für Technologie\\
|
||||
% Am Fasanengarten 5\\
|
||||
% 76131 Karlsruhe
|
||||
% \end{flushleft}
|
||||
% \newpage
|
||||
|
302
11-entwurfsheft-kolloquium/.gitignore
vendored
Normal file
|
@ -0,0 +1,302 @@
|
|||
## Core latex/pdflatex auxiliary files:
|
||||
*.aux
|
||||
*.lof
|
||||
*.log
|
||||
*.lot
|
||||
*.fls
|
||||
*.out
|
||||
*.toc
|
||||
*.fmt
|
||||
*.fot
|
||||
*.cb
|
||||
*.cb2
|
||||
.*.lb
|
||||
|
||||
## Intermediate documents:
|
||||
*.dvi
|
||||
*.xdv
|
||||
*-converted-to.*
|
||||
# these rules might exclude image files for figures etc.
|
||||
# *.ps
|
||||
# *.eps
|
||||
*.pdf
|
||||
!assets/*.pdf
|
||||
|
||||
## Generated if empty string is given at "Please type another file name for output:"
|
||||
.pdf
|
||||
|
||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||
*.bbl
|
||||
*.bcf
|
||||
*.blg
|
||||
*-blx.aux
|
||||
*-blx.bib
|
||||
*.run.xml
|
||||
|
||||
## Build tool auxiliary files:
|
||||
*.fdb_latexmk
|
||||
*.synctex
|
||||
*.synctex(busy)
|
||||
*.synctex.gz
|
||||
*.synctex.gz(busy)
|
||||
*.pdfsync
|
||||
|
||||
## Build tool directories for auxiliary files
|
||||
# latexrun
|
||||
latex.out/
|
||||
|
||||
## Auxiliary and intermediate files from other packages:
|
||||
# algorithms
|
||||
*.alg
|
||||
*.loa
|
||||
|
||||
# achemso
|
||||
acs-*.bib
|
||||
|
||||
# amsthm
|
||||
*.thm
|
||||
|
||||
# beamer
|
||||
*.nav
|
||||
*.pre
|
||||
*.snm
|
||||
*.vrb
|
||||
|
||||
# changes
|
||||
*.soc
|
||||
|
||||
# comment
|
||||
*.cut
|
||||
|
||||
# cprotect
|
||||
*.cpt
|
||||
|
||||
# elsarticle (documentclass of Elsevier journals)
|
||||
*.spl
|
||||
|
||||
# endnotes
|
||||
*.ent
|
||||
|
||||
# fixme
|
||||
*.lox
|
||||
|
||||
# feynmf/feynmp
|
||||
*.mf
|
||||
*.mp
|
||||
*.t[1-9]
|
||||
*.t[1-9][0-9]
|
||||
*.tfm
|
||||
|
||||
#(r)(e)ledmac/(r)(e)ledpar
|
||||
*.end
|
||||
*.?end
|
||||
*.[1-9]
|
||||
*.[1-9][0-9]
|
||||
*.[1-9][0-9][0-9]
|
||||
*.[1-9]R
|
||||
*.[1-9][0-9]R
|
||||
*.[1-9][0-9][0-9]R
|
||||
*.eledsec[1-9]
|
||||
*.eledsec[1-9]R
|
||||
*.eledsec[1-9][0-9]
|
||||
*.eledsec[1-9][0-9]R
|
||||
*.eledsec[1-9][0-9][0-9]
|
||||
*.eledsec[1-9][0-9][0-9]R
|
||||
|
||||
# glossaries
|
||||
*.acn
|
||||
*.acr
|
||||
*.glg
|
||||
*.glo
|
||||
*.gls
|
||||
*.glsdefs
|
||||
*.lzo
|
||||
*.lzs
|
||||
*.slg
|
||||
*.slo
|
||||
*.sls
|
||||
|
||||
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
||||
*.ist
|
||||
|
||||
# gnuplot
|
||||
*.gnuplot
|
||||
*.table
|
||||
|
||||
# gnuplottex
|
||||
*-gnuplottex-*
|
||||
|
||||
# gregoriotex
|
||||
*.gaux
|
||||
*.glog
|
||||
*.gtex
|
||||
|
||||
# htlatex
|
||||
*.4ct
|
||||
*.4tc
|
||||
*.idv
|
||||
*.lg
|
||||
*.trc
|
||||
*.xref
|
||||
|
||||
# hyperref
|
||||
*.brf
|
||||
|
||||
# knitr
|
||||
*-concordance.tex
|
||||
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
|
||||
# *.tikz
|
||||
*-tikzDictionary
|
||||
|
||||
# listings
|
||||
*.lol
|
||||
|
||||
# luatexja-ruby
|
||||
*.ltjruby
|
||||
|
||||
# makeidx
|
||||
*.idx
|
||||
*.ilg
|
||||
*.ind
|
||||
|
||||
# minitoc
|
||||
*.maf
|
||||
*.mlf
|
||||
*.mlt
|
||||
*.mtc[0-9]*
|
||||
*.slf[0-9]*
|
||||
*.slt[0-9]*
|
||||
*.stc[0-9]*
|
||||
|
||||
# minted
|
||||
_minted*
|
||||
*.pyg
|
||||
|
||||
# morewrites
|
||||
*.mw
|
||||
|
||||
# newpax
|
||||
*.newpax
|
||||
|
||||
# nomencl
|
||||
*.nlg
|
||||
*.nlo
|
||||
*.nls
|
||||
|
||||
# pax
|
||||
*.pax
|
||||
|
||||
# pdfpcnotes
|
||||
*.pdfpc
|
||||
|
||||
# sagetex
|
||||
*.sagetex.sage
|
||||
*.sagetex.py
|
||||
*.sagetex.scmd
|
||||
|
||||
# scrwfile
|
||||
*.wrt
|
||||
|
||||
# svg
|
||||
svg-inkscape/
|
||||
|
||||
# sympy
|
||||
*.sout
|
||||
*.sympy
|
||||
sympy-plots-for-*.tex/
|
||||
|
||||
# pdfcomment
|
||||
*.upa
|
||||
*.upb
|
||||
|
||||
# pythontex
|
||||
*.pytxcode
|
||||
pythontex-files-*/
|
||||
|
||||
# tcolorbox
|
||||
*.listing
|
||||
|
||||
# thmtools
|
||||
*.loe
|
||||
|
||||
# TikZ & PGF
|
||||
*.dpth
|
||||
*.md5
|
||||
*.auxlock
|
||||
|
||||
# titletoc
|
||||
*.ptc
|
||||
|
||||
# todonotes
|
||||
*.tdo
|
||||
|
||||
# vhistory
|
||||
*.hst
|
||||
*.ver
|
||||
|
||||
# easy-todo
|
||||
*.lod
|
||||
|
||||
# xcolor
|
||||
*.xcp
|
||||
|
||||
# xmpincl
|
||||
*.xmpi
|
||||
|
||||
# xindy
|
||||
*.xdy
|
||||
|
||||
# xypic precompiled matrices and outlines
|
||||
*.xyc
|
||||
*.xyd
|
||||
|
||||
# endfloat
|
||||
*.ttt
|
||||
*.fff
|
||||
|
||||
# Latexian
|
||||
TSWLatexianTemp*
|
||||
|
||||
## Editors:
|
||||
# WinEdt
|
||||
*.bak
|
||||
*.sav
|
||||
|
||||
# Texpad
|
||||
.texpadtmp
|
||||
|
||||
# LyX
|
||||
*.lyx~
|
||||
|
||||
# Kile
|
||||
*.backup
|
||||
|
||||
# gummi
|
||||
.*.swp
|
||||
|
||||
# KBibTeX
|
||||
*~[0-9]*
|
||||
|
||||
# TeXnicCenter
|
||||
*.tps
|
||||
|
||||
# auto folder when using emacs and auctex
|
||||
./auto/*
|
||||
*.el
|
||||
|
||||
# expex forward references with \gathertags
|
||||
*-tags.tex
|
||||
|
||||
# standalone packages
|
||||
*.sta
|
||||
|
||||
# Makeindex log files
|
||||
*.lpz
|
||||
|
||||
# xwatermark package
|
||||
*.xwm
|
||||
|
||||
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
|
||||
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
|
||||
# Uncomment the next line to have this generated file ignored.
|
||||
#*Notes.bib
|
36
11-entwurfsheft-kolloquium/.gitlab-ci.yml
Normal file
|
@ -0,0 +1,36 @@
|
|||
plantuml:
|
||||
stage: .pre
|
||||
image:
|
||||
name: plantuml/plantuml
|
||||
entrypoint: [""]
|
||||
script:
|
||||
- java -jar plantuml.jar -tpdf assets/diagrams/*.puml
|
||||
artifacts:
|
||||
paths:
|
||||
- assets
|
||||
|
||||
tex:
|
||||
stage: build
|
||||
image: texlive/texlive
|
||||
script:
|
||||
- mkdir public
|
||||
- make tex
|
||||
- mv *.pdf public
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
dependencies:
|
||||
- plantuml
|
||||
|
||||
pages:
|
||||
stage: deploy
|
||||
script:
|
||||
- echo Hello, World!
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
||||
dependencies:
|
||||
- tex
|
||||
|
34
11-entwurfsheft-kolloquium/CHANGELOG.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Changelog
|
||||
Alle Änderungen an diesem Projekt werden in dieser Datei dokumentiert.
|
||||
Die Versionsnummern folgt der Syntax in `sdqbeamer.cls`.
|
||||
|
||||
## [2022-05-03 v3.1.3]
|
||||
- Die Breite des Gruppennamens in der Fußzeile kann nun über `\groupnamewidth{}` gesteuert werden
|
||||
- FIX: zweizeilige Fußzeilen haben nun gleichmäßigen vertikalen Abstand (Issue #16 in Gitlab)
|
||||
|
||||
## [2021-08-10 v3.1.2]
|
||||
- FIX: framesubtitle wird nun angezeigt (Issue #6 in Gitlab)
|
||||
|
||||
## [2020-12-08 v3.1.1]
|
||||
- FIX: Titelbild (Issue #4 in Gitlab)
|
||||
|
||||
## [2020-12-07 v3.1]
|
||||
- Umgebung ``contentblock`` (farbloser Block mit fetter Überschrift) hinzugefügt
|
||||
- Farbboxen (``greenblock``, ``blueblock``, …) hinzugefügt
|
||||
- Abstufungen der KIT-Farben in 10er-Schritten entsprechend der Gestaltungsrichtlinien eingeführt
|
||||
- FIX: Navigationspunkte für Subsections in eine Zeile gesetzt, um vertikal Platz zu sparen
|
||||
- FIX: ``inputenc`` an den Anfang von ``sdqbeamer.cls`` verschoben
|
||||
|
||||
## [2020-11-16 v3.0]
|
||||
- Seitenformat 16:10 hinzugefügt
|
||||
- Umstellung auf KIT-Design vom 1. August 2020
|
||||
- Anpassung auf neues Farbschema und Maße
|
||||
- neues Titelbild aus der KIT-Bildwelt
|
||||
- Neue Optionen:
|
||||
- durch `smallfoot` und `bigfoot` kann die Schriftgröße der Fußzeile gesteuert werden
|
||||
- durch `navbarkit` kann eine Fußzeile nach KIT-Vorgaben erzwungen werden
|
||||
- Deutsch (`de`) ist nun die Standard-Option
|
||||
- Ordner `templates` wurde gelöscht und die Inhalte in `sdqbeamer.cls` integriert
|
||||
- Globale Größe auf 10 pt verringert (vorher: 11 pt), da der beschreibbare Bereich im Vergleich zur 2009er Version kleiner geworden ist
|
||||
- SDQ-spezifische Logos und Titelbilder entfernt. Diese sind ab sofort im Branch »sdq« verfügbar.
|
||||
- Fix: Zeilenumbruch bei Titel in der Fußzeile repariert
|
18
11-entwurfsheft-kolloquium/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
|||
MAIN = presentation
|
||||
FLAGS = -pdf
|
||||
|
||||
all: clean compile
|
||||
compile: diagram tex
|
||||
clean: clean-diagram clean-tex
|
||||
|
||||
dev:
|
||||
latexmk $(FLAGS) -pvc $(MAIN)
|
||||
tex:
|
||||
latexmk $(FLAGS) $(MAIN)
|
||||
diagram:
|
||||
java -jar plantuml.jar -tpdf assets/diagrams/*.puml
|
||||
clean-tex:
|
||||
latexmk -C
|
||||
clean-diagram:
|
||||
find assets/diagrams -type f -not -name '*.puml' -delete
|
||||
|
118
11-entwurfsheft-kolloquium/README.md
Normal file
|
@ -0,0 +1,118 @@
|
|||
LaTeX-Vorlage für Präsentationen
|
||||
================================
|
||||
|
||||
Das vorliegende Paket dient als Vorlage für Präsentationen im [Corporate Design des KIT](https://intranet.kit.edu/gestaltungsrichtlinien.php) (Fassung vom 1. August 2020).
|
||||
|
||||
Es wird an der Forschungsgruppe [DSiS](https://dsis.kastel.kit.edu) an der KIT-Fakultät für Informatik entwickelt und basiert auf [LaTeX Beamer](https://ctan.org/pkg/beamer).
|
||||
|
||||
Autor: [Dr.-Ing. Erik Burger](https://dsis.kastel.kit.edu/staff_erik_burger.php)
|
||||
mit Beiträgen von Christian Hammer, Klaus Krogmann und Maximilian Schambach
|
||||
|
||||
Siehe https://sdqweb.ipd.kit.edu/wiki/Dokumentvorlagen
|
||||
|
||||
Hinweise, Verbesserungsvorschläge
|
||||
=================================
|
||||
|
||||
Bitte verwenden Sie das [Issue-Tracking-System von Gitlab](https://git.scc.kit.edu/i43/dokumentvorlagen/praesentationen/beamer/-/issues), um auf Probleme mit der Vorlage hinzuweisen oder Erweiterungswünsche zu äußern. Sie können gerne auch eine Änderung per Merge-Request vorschlagen.
|
||||
|
||||
Verwendung
|
||||
==========
|
||||
|
||||
Optionen der Dokumentklasse `sdqbeamer`
|
||||
-----------------------------------------
|
||||
Durch die folgenden Optionen kann das Seitenverhältnis der Folien bestimmt werden:
|
||||
|
||||
| Seitenverhältnis | Option |
|
||||
| ---------------- | ------------------- |
|
||||
| 16:9 | `16:9` (Standard) |
|
||||
| 16:10 | `16:10` |
|
||||
| 4:3 | `4:3` |
|
||||
|
||||
Die Schriftgröße in der Fußzeile ist standardmäßig größer gewählt, als in den Gestaltungsrichtlinien vorgegeben. Diese Vorgabe kann durch die Option `smallfoot` erzwungen werden.
|
||||
|
||||
| Schriftgröße Fußzeile | Option |
|
||||
| ----------------------| -------------------- |
|
||||
| etwas größer (12pt) | `bigfoot` (Standard) |
|
||||
| KIT-Vorgabe (9pt) | `smallfoot` |
|
||||
|
||||
Die Plazierung der Navigationsleiste kann durch folgende Optionen beeinflußt werden:
|
||||
|
||||
| Position | Option | Bemerkung |
|
||||
| ------------------------ | ---------------- | ------------------------------------------ |
|
||||
| oberhalb der Trennlinie | `navbarinline` | Standard |
|
||||
| unterhalb der Trennlinie | `navbarinfooter` | keine Subsection-Punkte, Größe `smallfoot` |
|
||||
| Seitenleiste links | `navbarside` | keine Subsection-Punkte |
|
||||
| keine Navigationsleiste | `navbaroff` | |
|
||||
| KIT-Vorgabe | `navbarkit` | entspricht `navbaroff` und `smallfoot` |
|
||||
|
||||
Als Sprache sind Deutsch und Englisch verfügbar. Durch die Sprachwahl werden automatisch die passenden Logos und Formate (z.B. Datum) gewählt.
|
||||
|
||||
| Sprache | |
|
||||
| -------- |---------------- |
|
||||
| Deutsch | `de` (Standard) |
|
||||
| Englisch | `en` |
|
||||
|
||||
Beispiel: `\documentclass[de,16:9,navbarinline]{sdqbeamer}`
|
||||
|
||||
Titelbild
|
||||
---------
|
||||
|
||||
Das Bild auf der Titelfolie kann mit dem Befehl
|
||||
|
||||
`\titleimage{myimage}` (ohne Dateiendung)
|
||||
|
||||
gesetzt werden. Um ein eigenes Bild zu verwenden, bitte die Datei (z.B. `myimage.jpg`) ins `logos/`-Verzeichnis legen und den Befehl anpassen. Mitgeliefert wird ein generisches Bild aus der KIT-Bildwelt (https://intranet.kit.edu/gestaltungsrichtlinien.php) in der Datei `logos/banner_2020_kit.jpg`. Falls kein Titelbild eingefügt werden soll, bitte `\titleimage{}` setzen.
|
||||
|
||||
Für 16:9-Folien sollte das Verhältnis des Bildes 160:37 betragen, für 4:3-Folien 63:20. Es können auch breitere Bilder verwendet werden, da das Titelbild auf die Höhe des Rahmens skaliert und zentriert wird.
|
||||
|
||||
Logo und Name Abteilung/KIT-Fakultät/Institut
|
||||
---------------------------------------------
|
||||
|
||||
Das Logo rechts oben auf der Titelfolie kann mit dem folgenden Befehl gesetzt werden:
|
||||
|
||||
`\grouplogo{mylogo}` (ohne Dateiendung)
|
||||
|
||||
Um ein eigenes Logo zu verwenden, bitte die Datei (z.B. `mylogo.pdf`) in das Verzeichnis `logos/` legen und den Befehl anpassen. Falls kein Logo eingefügt werden soll, bitte `\grouplogo{}` setzen.
|
||||
|
||||
Der Gruppenname kann mit folgendem Befehl gesetzt werden:
|
||||
|
||||
`\groupname{Software Design and Quality}`
|
||||
|
||||
Der Gruppenname erscheint in der Fußzeile rechts unten. Lange Namen werden in zwei Zeilen umgebrochen. Falls der Gruppenname leer gelassen wird (`\groupname{}`), wird die volle Breite der Fußzeile für Autornamen und Titel verwendet.
|
||||
|
||||
Die Standardbreite des Gruppennamens sind 50 mm. Sie kann mit
|
||||
|
||||
`\groupnamewidth{80mm}`
|
||||
|
||||
verändert werden, wodurch sich auch die Breite des Textfeldes mit Autor und Titel entsprechend ändert. Umbrüche sind mit `\\` möglich. Statt zweizeiliger Fußzeilen empfiehlt sich eventuell die Option `smallfoot`.
|
||||
|
||||
LaTeX allgemein
|
||||
---------------
|
||||
Siehe https://sdqweb.ipd.kit.edu/wiki/LaTeX
|
||||
|
||||
Dateistruktur
|
||||
============
|
||||
`presentation.tex`
|
||||
------------------
|
||||
Hauptdatei des LaTeX-Dokuments.
|
||||
|
||||
`presentation.bib`
|
||||
-------------
|
||||
Beispieldatei für BibTeX-Referenzen
|
||||
https://sdqweb.ipd.kit.edu/wiki/BibTeX-Literaturlisten
|
||||
|
||||
`sdqbeamer.cls`
|
||||
-----------------
|
||||
Dokumentklasse für Präsentationen im KIT-Design.
|
||||
|
||||
`logos/`
|
||||
--------
|
||||
In diesem Verzeichnis befinden das KIT-Logo als PDF sowie das Hintergrundbild der Titelfolie als JPG.
|
||||
|
||||
`CHANGELOG.md`
|
||||
--------------
|
||||
Dokumentation der Änderungen in den jeweiligen Versionen.
|
||||
|
||||
`README.md`
|
||||
-----------
|
||||
Dieser Text.
|
3
11-entwurfsheft-kolloquium/assets/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
diagrams/*
|
||||
!diagrams/*.puml
|
||||
|
3
11-entwurfsheft-kolloquium/assets/.gitingnore
Normal file
|
@ -0,0 +1,3 @@
|
|||
diagrams/*
|
||||
!diagrams/*.puml
|
||||
|