Add legal texts. Add parametrized monitoring routes.

This commit is contained in:
Jan Eitzinger 2022-02-03 09:39:04 +01:00
parent c98863f22e
commit 6025bbdecd
6 changed files with 712 additions and 155 deletions

View File

@ -6,7 +6,6 @@ import (
"github.com/ClusterCockpit/cc-backend/auth" "github.com/ClusterCockpit/cc-backend/auth"
"github.com/ClusterCockpit/cc-backend/config" "github.com/ClusterCockpit/cc-backend/config"
"github.com/ClusterCockpit/cc-backend/graph"
"github.com/ClusterCockpit/cc-backend/templates" "github.com/ClusterCockpit/cc-backend/templates"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
@ -21,7 +20,7 @@ type Route struct {
Setup func(i InfoType, r *http.Request) InfoType Setup func(i InfoType, r *http.Request) InfoType
} }
func setupRoutes(router *mux.Router, resolver *graph.Resolver, routes []Route) { func setupRoutes(router *mux.Router, routes []Route) {
for _, route := range routes { for _, route := range routes {
router.HandleFunc(route.Route, func(rw http.ResponseWriter, r *http.Request) { router.HandleFunc(route.Route, func(rw http.ResponseWriter, r *http.Request) {
conf, err := config.GetUIConfig(r) conf, err := config.GetUIConfig(r)

327
server.go
View File

@ -126,6 +126,50 @@ var programConfig ProgramConfig = ProgramConfig{
}, },
} }
func setupJobRoute(i InfoType, r *http.Request) InfoType {
i["id"] = mux.Vars(r)["id"]
return i
}
func setupUserRoute(i InfoType, r *http.Request) InfoType {
i["id"] = mux.Vars(r)["id"]
return i
}
func setupClusterRoute(i InfoType, r *http.Request) InfoType {
vars := mux.Vars(r)
i["id"] = vars["cluster"]
i["cluster"] = vars["cluster"]
from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to")
if from != "" || to != "" {
i["from"] = from
i["to"] = to
}
return i
}
func setupNodeRoute(i InfoType, r *http.Request) InfoType {
vars := mux.Vars(r)
i["cluster"] = vars["cluster"]
i["hostname"] = vars["hostname"]
from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to")
if from != "" || to != "" {
i["from"] = from
i["to"] = to
}
return i
}
var routes []Route = []Route{
{"/monitoring/jobs/", "monitoring/jobs.tmpl", "Jobs - ClusterCockpit", true, func(i InfoType, r *http.Request) InfoType { return i }},
{"/monitoring/job/{id:[0-9]+}", "monitoring/job.tmpl", "Job <ID> - ClusterCockpit", false, setupJobRoute},
{"/monitoring/users/", "monitoring/list.tmpl", "Users - ClusterCockpit", true, func(i InfoType, r *http.Request) InfoType { i["listType"] = "USER"; return i }},
{"/monitoring/projects/", "monitoring/list.tmpl", "Projects - ClusterCockpit", true, func(i InfoType, r *http.Request) InfoType { i["listType"] = "PROJECT"; return i }},
{"/monitoring/user/{id}", "monitoring/user.tmpl", "User <ID> - ClusterCockpit", true, setupUserRoute},
{"/monitoring/systems/{cluster}", "monitoring/systems.tmpl", "Cluster <ID> - ClusterCockpit", false, setupClusterRoute},
{"/monitoring/node/{cluster}/{hostname}", "monitoring/node.tmpl", "Node <ID> - ClusterCockpit", false, setupNodeRoute},
}
func main() { func main() {
var flagReinitDB, flagStopImmediately, flagSyncLDAP bool var flagReinitDB, flagStopImmediately, flagSyncLDAP bool
var flagConfigFile string var flagConfigFile string
@ -271,7 +315,6 @@ func main() {
handleGetLogin := func(rw http.ResponseWriter, r *http.Request) { handleGetLogin := func(rw http.ResponseWriter, r *http.Request) {
templates.Render(rw, r, "login.tmpl", &templates.Page{ templates.Render(rw, r, "login.tmpl", &templates.Page{
Title: "Login", Title: "Login",
Login: &templates.LoginPage{},
}) })
} }
@ -284,8 +327,19 @@ func main() {
r.Handle("/playground", graphQLPlayground) r.Handle("/playground", graphQLPlayground)
r.Handle("/login", auth.Login(db)).Methods(http.MethodPost) r.Handle("/login", auth.Login(db)).Methods(http.MethodPost)
r.HandleFunc("/login", handleGetLogin).Methods(http.MethodGet) r.HandleFunc("/login", handleGetLogin).Methods(http.MethodGet)
r.HandleFunc("/logout", auth.Logout).Methods(http.MethodPost) r.HandleFunc("/logout", auth.Logout).Methods(http.MethodPost)
r.HandleFunc("/imprint", func(rw http.ResponseWriter, r *http.Request) {
templates.Render(rw, r, "imprint.tmpl", &templates.Page{
Title: "Imprint",
})
})
r.HandleFunc("/privacy", func(rw http.ResponseWriter, r *http.Request) {
templates.Render(rw, r, "privacy.tmpl", &templates.Page{
Title: "Privacy",
})
})
secured := r.PathPrefix("/").Subrouter() secured := r.PathPrefix("/").Subrouter()
if !programConfig.DisableAuthentication { if !programConfig.DisableAuthentication {
@ -319,7 +373,7 @@ func main() {
}) })
}) })
monitoringRoutes(secured, resolver) setupRoutes(secured, routes)
api.MountRoutes(secured) api.MountRoutes(secured)
r.PathPrefix("/").Handler(http.FileServer(http.Dir(programConfig.StaticFiles))) r.PathPrefix("/").Handler(http.FileServer(http.Dir(programConfig.StaticFiles)))
@ -395,27 +449,6 @@ func main() {
log.Print("Gracefull shutdown completed!") log.Print("Gracefull shutdown completed!")
} }
func prepareRoute(r *http.Request) (map[string]interface{}, map[string]interface{}, error) {
conf, err := config.GetUIConfig(r)
if err != nil {
return nil, nil, err
}
infos := map[string]interface{}{
"admin": true,
}
if user := auth.GetUser(r.Context()); user != nil {
infos["username"] = user.Username
infos["admin"] = user.HasRole(auth.RoleAdmin)
} else {
infos["username"] = false
infos["admin"] = false
}
return conf, infos, nil
}
func buildFilterPresets(query url.Values) map[string]interface{} { func buildFilterPresets(query url.Values) map[string]interface{} {
filterPresets := map[string]interface{}{} filterPresets := map[string]interface{}{}
@ -465,152 +498,152 @@ func buildFilterPresets(query url.Values) map[string]interface{} {
return filterPresets return filterPresets
} }
func monitoringRoutes(router *mux.Router, resolver *graph.Resolver) { // func monitoringRoutes(router *mux.Router, resolver *graph.Resolver) {
router.HandleFunc("/monitoring/jobs/", func(rw http.ResponseWriter, r *http.Request) { // router.HandleFunc("/monitoring/jobs/", func(rw http.ResponseWriter, r *http.Request) {
conf, infos, err := prepareRoute(r) // conf, infos, err := prepareRoute(r)
if err != nil { // if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError) // http.Error(rw, err.Error(), http.StatusInternalServerError)
return // return
} // }
templates.Render(rw, r, "monitoring/jobs.tmpl", &templates.Page{ // templates.Render(rw, r, "monitoring/jobs.tmpl", &templates.Page{
Title: "Jobs - ClusterCockpit", // Title: "Jobs - ClusterCockpit",
Config: conf, // Config: conf,
Infos: infos, // Infos: infos,
FilterPresets: buildFilterPresets(r.URL.Query()), // FilterPresets: buildFilterPresets(r.URL.Query()),
}) // })
}) // })
router.HandleFunc("/monitoring/job/{id:[0-9]+}", func(rw http.ResponseWriter, r *http.Request) { // router.HandleFunc("/monitoring/job/{id:[0-9]+}", func(rw http.ResponseWriter, r *http.Request) {
conf, infos, err := prepareRoute(r) // conf, infos, err := prepareRoute(r)
if err != nil { // if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError) // http.Error(rw, err.Error(), http.StatusInternalServerError)
return // return
} // }
id := mux.Vars(r)["id"] // id := mux.Vars(r)["id"]
job, err := resolver.Query().Job(r.Context(), id) // job, err := resolver.Query().Job(r.Context(), id)
if err != nil { // if err != nil {
http.Error(rw, err.Error(), http.StatusNotFound) // http.Error(rw, err.Error(), http.StatusNotFound)
return // return
} // }
infos["id"] = id // infos["id"] = id
infos["jobId"] = job.JobID // infos["jobId"] = job.JobID
infos["clusterId"] = job.Cluster // infos["clusterId"] = job.Cluster
templates.Render(rw, r, "monitoring/job.tmpl", &templates.Page{ // templates.Render(rw, r, "monitoring/job.tmpl", &templates.Page{
Title: fmt.Sprintf("Job %d - ClusterCockpit", job.JobID), // Title: fmt.Sprintf("Job %d - ClusterCockpit", job.JobID),
Config: conf, // Config: conf,
Infos: infos, // Infos: infos,
}) // })
}) // })
router.HandleFunc("/monitoring/users/", func(rw http.ResponseWriter, r *http.Request) { // router.HandleFunc("/monitoring/users/", func(rw http.ResponseWriter, r *http.Request) {
conf, infos, err := prepareRoute(r) // conf, infos, err := prepareRoute(r)
if err != nil { // if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError) // http.Error(rw, err.Error(), http.StatusInternalServerError)
return // return
} // }
infos["listType"] = "USER" // infos["listType"] = "USER"
templates.Render(rw, r, "monitoring/list.tmpl", &templates.Page{ // templates.Render(rw, r, "monitoring/list.tmpl", &templates.Page{
Title: "Users - ClusterCockpit", // Title: "Users - ClusterCockpit",
Config: conf, // Config: conf,
FilterPresets: buildFilterPresets(r.URL.Query()), // FilterPresets: buildFilterPresets(r.URL.Query()),
Infos: infos, // Infos: infos,
}) // })
}) // })
router.HandleFunc("/monitoring/projects/", func(rw http.ResponseWriter, r *http.Request) { // router.HandleFunc("/monitoring/projects/", func(rw http.ResponseWriter, r *http.Request) {
conf, infos, err := prepareRoute(r) // conf, infos, err := prepareRoute(r)
if err != nil { // if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError) // http.Error(rw, err.Error(), http.StatusInternalServerError)
return // return
} // }
infos["listType"] = "PROJECT" // infos["listType"] = "PROJECT"
templates.Render(rw, r, "monitoring/list.tmpl", &templates.Page{ // templates.Render(rw, r, "monitoring/list.tmpl", &templates.Page{
Title: "Projects - ClusterCockpit", // Title: "Projects - ClusterCockpit",
Config: conf, // Config: conf,
FilterPresets: buildFilterPresets(r.URL.Query()), // FilterPresets: buildFilterPresets(r.URL.Query()),
Infos: infos, // Infos: infos,
}) // })
}) // })
router.HandleFunc("/monitoring/user/{id}", func(rw http.ResponseWriter, r *http.Request) { // router.HandleFunc("/monitoring/user/{id}", func(rw http.ResponseWriter, r *http.Request) {
conf, infos, err := prepareRoute(r) // conf, infos, err := prepareRoute(r)
if err != nil { // if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError) // http.Error(rw, err.Error(), http.StatusInternalServerError)
return // return
} // }
id := mux.Vars(r)["id"] // id := mux.Vars(r)["id"]
// TODO: One could check if the user exists, but that would be unhelpfull if authentication // // TODO: One could check if the user exists, but that would be unhelpfull if authentication
// is disabled or the user does not exist but has started jobs. // // is disabled or the user does not exist but has started jobs.
infos["username"] = id // infos["username"] = id
templates.Render(rw, r, "monitoring/user.tmpl", &templates.Page{ // templates.Render(rw, r, "monitoring/user.tmpl", &templates.Page{
Title: fmt.Sprintf("User %s - ClusterCockpit", id), // Title: fmt.Sprintf("User %s - ClusterCockpit", id),
Config: conf, // Config: conf,
Infos: infos, // Infos: infos,
FilterPresets: buildFilterPresets(r.URL.Query()), // FilterPresets: buildFilterPresets(r.URL.Query()),
}) // })
}) // })
router.HandleFunc("/monitoring/systems/", func(rw http.ResponseWriter, r *http.Request) { // router.HandleFunc("/monitoring/systems/", func(rw http.ResponseWriter, r *http.Request) {
// TODO: List all clusters? // // TODO: List all clusters?
http.Redirect(rw, r, "/", http.StatusTemporaryRedirect) // http.Redirect(rw, r, "/", http.StatusTemporaryRedirect)
}) // })
router.HandleFunc("/monitoring/systems/{cluster}", func(rw http.ResponseWriter, r *http.Request) { // router.HandleFunc("/monitoring/systems/{cluster}", func(rw http.ResponseWriter, r *http.Request) {
conf, infos, err := prepareRoute(r) // conf, infos, err := prepareRoute(r)
if err != nil { // if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError) // http.Error(rw, err.Error(), http.StatusInternalServerError)
return // return
} // }
vars := mux.Vars(r) // vars := mux.Vars(r)
infos["cluster"] = vars["cluster"] // infos["cluster"] = vars["cluster"]
from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to") // from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to")
if from != "" || to != "" { // if from != "" || to != "" {
infos["from"] = from // infos["from"] = from
infos["to"] = to // infos["to"] = to
} // }
templates.Render(rw, r, "monitoring/systems.tmpl", &templates.Page{ // templates.Render(rw, r, "monitoring/systems.tmpl", &templates.Page{
Title: fmt.Sprintf("Cluster %s - ClusterCockpit", vars["cluster"]), // Title: fmt.Sprintf("Cluster %s - ClusterCockpit", vars["cluster"]),
Config: conf, // Config: conf,
Infos: infos, // Infos: infos,
}) // })
}) // })
router.HandleFunc("/monitoring/node/{cluster}/{hostname}", func(rw http.ResponseWriter, r *http.Request) { // router.HandleFunc("/monitoring/node/{cluster}/{hostname}", func(rw http.ResponseWriter, r *http.Request) {
conf, infos, err := prepareRoute(r) // conf, infos, err := prepareRoute(r)
if err != nil { // if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError) // http.Error(rw, err.Error(), http.StatusInternalServerError)
return // return
} // }
vars := mux.Vars(r) // vars := mux.Vars(r)
infos["cluster"] = vars["cluster"] // infos["cluster"] = vars["cluster"]
infos["hostname"] = vars["hostname"] // infos["hostname"] = vars["hostname"]
from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to") // from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to")
if from != "" || to != "" { // if from != "" || to != "" {
infos["from"] = from // infos["from"] = from
infos["to"] = to // infos["to"] = to
} // }
templates.Render(rw, r, "monitoring/node.tmpl", &templates.Page{ // templates.Render(rw, r, "monitoring/node.tmpl", &templates.Page{
Title: fmt.Sprintf("Host %s - ClusterCockpit", vars["hostname"]), // Title: fmt.Sprintf("Host %s - ClusterCockpit", vars["hostname"]),
Config: conf, // Config: conf,
Infos: infos, // Infos: infos,
}) // })
}) // })
} // }
func loadEnv(file string) error { func loadEnv(file string) error {
f, err := os.Open(file) f, err := os.Open(file)

205
templates/imprint.tmpl Normal file
View File

@ -0,0 +1,205 @@
{{define "navigation"}}
{{""}}
{{end}}
{{define "content"}}
<div class="container" style="margin-top:80px;margin-bottom:80px;">
<div class="row legal">
<div class="col-xs-12">
<h1>Imprint</h1>
<h2>Website owner</h2>
<p>name</p>
<address>
address
</address>
<ul>
<li>
Phone: +49-</li>
<li>
Fax: +49-</li>
<li>
E-Mail:
</li>
</ul>
<h3>Represented by</h3>
<p>
Your institution
</p>
<p>
Notice
</p>
<h3>Website Contact (Webmaster)</h3>
<p>name</p>
<ul>
<li>
Phone: +49-
</li>
<li>
E-Mail:
</li>
</ul>
<h3>Responsible controlling authority</h3>
<address>
address
</address>
<p>
Website: </p>
<h3>ID numbers</h3>
<table class="table">
<tbody>
<tr>
<th scope="row">VAT identification number</th>
<td>xxx</td>
</tr>
<tr>
<th scope="row">Tax number</th>
<td>xxx</td>
</tr>
<tr>
<th scope="row">DUNS number</th>
<td>xxx</td>
</tr>
<tr>
<th scope="row">EORI number</th>
<td>xxx</td>
</tr>
<tr>
<th scope="row">Bank details:</th>
<td>xxx
<ul>
<li>SWIFT/BIC-Code: </li>
<li>IBAN: </li>
</ul>
</td>
</tr>
</tbody>
</table>
<h2>Reporting misuse of computers and network resources</h2>
<p>
Should you become aware of any kind of misuse of computers or network resources at XXX,
<a href="URL">please inform the department responsible for computer security</a> immediately.
<h2>Copyright</h2>
<p>
Unless specified otherwise, all pages of the INSTITUTION
website are protected by copyright. This applies in
particular to texts, images, charts, and files
containing style, sound, video, or animation data; it
also includes the design of the website.
</p>
<p>
Reproduction or use of (parts) of the web pages in
electronic or printed form and their publication
(including on the Internet) is subject to prior
approval.
</p>
<p>
Press releases, publications, scripts and information
on lectures may be reprinted and evaluated provided
that the source is indicated. Furthermore, images,
charts, and files containing text or other information,
may, in part or in their entirety, be subject to the
copyright of third parties.
</p>
<p>
All registered brands and trademarks mentioned on this
website and possibly protected by third parties are
subject without restriction to the respective
applicable trademark law and the property rights of
their respective owners. The mere mention of trademarks
on this website does not indicate that they are not
protected by third party rights.
</p>
<h2>Exclusion of liability</h2>
<p>
This imprint only belongs to the following website:<br>
<strong><em>DOMAIN</em></strong><br> The website owner
is not responsible for other websites, that are not
listet above.
</p>
<p>
The operator has compiled and verified all information
provided with great care. However, we cannot assume
liability or furnish a guarantee that the data is
correct, complete or up-to-date, or regarding the
quality or constant availability of the information
provided.
</p>
<p>
We will not be liable for any damages arising from
computer viruses or the installation and use of
software when accessing or downloading data from this
website.
</p>
<p>
Websites credited to an author reflect the opinions and insights of that author.
</p>
<p>
The operator expressly reserves the right to change,
amend or delete individual web pages, services or the
entire website without prior notice or to interrupt or
terminate the publication.
</p>
<h2>Links and references (disclaimer)</h2>
<p>
The operator is only responsible for the original
content provided in accordance with the applicable
laws. This original content is to be distinguished from
links to the websites of other operators. Through these
references marked as external links, the
operator enables visitors to access third-party
content.
</p>
<p>
The operator is not responsible for this third-party
content as the operator does not initiate the data
transmission, does not choose the recipient of the
information and does not select or have any influence
on the information transmitted. The methods used to
provide access and link to this third-party information
also do not involve any automatic short-term storage,
resulting in a full exclusion of any liability for
third-party content on the operators part.
</p>
<p>
When links to these websites were first incorporated,
however, the authors of the relevant websites or the
operators editors reviewed the external content to
ascertain whether it would possibly entail liability
under civil or criminal law. Should the operator become
aware or be made aware by others that the content of a
website linked from this site could constitute a civil
or criminal law violation, then the link will be
immediately removed as long as this is technically
feasible and within reasonable expectation.
</p>
<p>
Liability for illegal, inaccurate or incomplete content
and for damages resulting from the use or non-use of
information provided by third parties shall lie
exclusively with the respective operators of the
linked sites.
</p>
</div>
</div>
</div>
{{end}}

View File

@ -5,6 +5,7 @@
{{define "stylesheets"}} {{define "stylesheets"}}
<link rel='stylesheet' href='/build/jobs.css'> <link rel='stylesheet' href='/build/jobs.css'>
{{end}} {{end}}
{{define "javascript"}} {{define "javascript"}}
<script> <script>
const filterPresets = {{ .FilterPresets }}; const filterPresets = {{ .FilterPresets }};

322
templates/privacy.tmpl Normal file
View File

@ -0,0 +1,322 @@
{{define "navigation"}}
{{""}}
{{end}}
{{define "content"}}
<div class="container" style="margin-top:80px;margin-bottom:80px;">
<div class="row legal">
<div class="col-md">
<h1>Privacy</h1>
<p>
INSTITUION is
responsible for its websites within the meaning of the
General Data Protection Regulation (GDPR) and other
national data protection laws as well as other data
protection regulations. It is legally represented by
its XX. For contact details, please consult the
YYY.
</p>
<p>
The respective INSTITUION institutions are responsible for
any content they make available on the websites of
INSTITUION. For questions related to specific content,
please contact the person responsible as named
LINK of this web page.
</p>
<h2>Name and address of the Data Protection Officer</h2>
<address>
address
</address>
<ul>
<li>Telefon: </span> +49 </li>
<li>Fax:</span> +49 </li>
<li>E-Mail:</li>
</ul>
<h2>General information on data processing</h2>
<h3>Scope of processing of personal data</h3>
<p>
We only process our users personal data to the extent
necessary to provide services, content and a functional
website. As a rule, personal data are only processed after
the user gives their consent. An exception applies in those
cases where it is impractical to obtain the users
prior consent and the processing of such data is
permitted by law.
</p>
<h3>Legal basis for the processing of personal data</h3>
<p>
Art. 6 (1) (a) of the EU General Data Protection Regulation
(GDPR) forms the legal basis for us to obtain the
consent of a data subject for their personal data to be
processed.<br> When processing personal data required for
the performance of a contract in which the contractual
party is the data subject, Art. 6 (1) (b) GDPR forms the
legal basis. This also applies if data has to be processed
in order to carry out pre-contractual activities.<br> Art.
6 (1) (c) GDPR forms the legal basis if personal data has
to be processed in order to fulfil a legal obligation on
the part of our organisation.<br> Art. 6 (1) (d) GDPR forms
the legal basis in the case that vital interests of the
data subject or another natural person make the processing
of personal data necessary.<br> If data processing is
necessary in order to protect the legitimate interests of
our organisation or of a third party and if the interests,
basic rights and fundamental freedoms of the data subject
do not outweigh the interests mentioned above, Art. 6 (1)
(f) GDPR forms the legal basis for such data processing.
</p>
<h3>Deletion of data and storage period</h3>
<p>
The personal data of the data subject are deleted or
blocked as soon as the reason for storing them ceases
to exist. Storage beyond this time period may occur if
provided for by European or national legislators in
directives under Union legislation, laws or other
regulations to which the data controller is subject.
Such data are also blocked or deleted if a storage period
prescribed by one of the above-named rules expires,
unless further storage of the data is necessary for
entering into or performing a contract.
</p>
<h2>Provision of the website and generation of log files</h2>
<h3>Description and scope of data processing</h3>
<p>
Each time our website is accessed, our system
automatically collects data and information from
the users computer system.<br> In this context, the
following data are collected:
</p>
<ul>
<li>
Address (URL) of the website from which the file was requested
</li>
<li>
Name of the retrieved file
</li>
<li>
Date and time of the request
</li>
<li>
Data volume transmitted
</li>
<li>
Access status (file transferred, file not found, etc.)
</li>
<li>
Description of the type of web browser and/or operating system used
</li>
<li>
Anonymised IP address of the requesting computer
</li>
</ul>
<p>
The data stored are required exclusively for technical or
statistical purposes; no comparison with other data or
disclosure to third parties occurs, not even in part.
The data are stored in our systems log files. This is not
the case for the users IP addresses or other data
that make it possible to assign the data to a specific
user: before data are stored, each dataset is anonymised by
changing the IP address. These data are not stored
together with other personal data .
</p>
<h3>Legal basis for data processing</h3>
<p>
The legal basis for the temporary storage of data and
logfiles is §§ 14, 15 TMG, § 100 Abs. 1 TKG and Art. 4
BayDSG following the tasks of Art. 11 BayEGovG and Art. 7
and 34 BayHO
</p>
<h3>Purpose of data processing</h3>
<p>
The temporary storage of the IP address by the system is
necessary in order to deliver the website to the
users computer. For this purpose, the users IP address
must remain stored for the duration of the session.<br> The
storage of such data in log files takes place in order to
ensure the websites functionality. These data also serve
to help us optimise the website and ensure that our IT
systems are secure. They are not evaluated for marketing
purposes in this respect.
</p>
<h3>Storage period</h3>
<p>
Data are deleted as soon as they are no longer necessary
for fulfilling the purpose for which they were
collected. If data have been collected for the purpose of
providing the website, they are deleted at the end of the
respective session.<br> If data are stored in log files,
they are deleted at the latest after seven days. A longer
storage period is possible. In this case, the users IP
addresses are deleted or masked so that they can no longer
be assigned to the client accessing the website.
</p>
<h3>Options for filing an objection or requesting removal</h3>
<p>
The collection of data for the purpose of providing the
website and the storage of such data in log files is
essential to the websites operation. As a consequence,
the user has no possibility to object.
</p>
<h2>Use of cookies</h2>
<h3>Description and scope of data processing</h3>
<p>
Our website uses cookies. Cookies are text files that are
saved in the users web browser or by the web browser
on the users computer system. When a user accesses a
website, a cookie can be stored in the users operating
system. This cookie contains a character string that allows
the unique identification of the browser when the
website is accessed again.
</p>
<p>
We use cookies to make our website more user-friendly. Some
parts of our website require that the requesting browser
can also be identified after changing pages.<br> During
this process, the following data are stored in the cookies
and transmitted:
</p>
<ul>
<li>
Log-in information (only in the case of protected information that is made available exclusively to FAU members)
</li>
</ul>
<p>
Technical measures are taken to pseudonymise user data
collected in this way. This means that the data can no
longer be assigned to the user. The data are not stored
together with other personal data of the user.<br> When
accessing our website, a banner informs users that cookies
are used for analysis purposes and makes reference to this
data protection policy. In connection with this, users are
also instructed how they can block the storage of cookies
in their browser settings.
</p>
<h3>Legal basis for data processing</h3>
<p>
The legal basis for the temporary storage of data and
logfiles is §§ 14, 15 TMG, § 100 Abs. 1 TKG and Art. 4
BayDSG following the tasks of Art. 11 BayEGovG and
Art. 7 and 34 BayHO
</p>
<h3>Purpose of data processing</h3>
<p>
Analysis cookies are used for the purpose of improving the
quality of our website and its content. We learn
through the analysis cookies how the website is used and in
this way can continuously optimise our web presence.
</p>
<h3>Storage period, options for filing an objection or requesting removal</h3>
<p>
As cookies are stored on the users computer and are
transmitted from it to our website, users have full
control over the use of cookies. You can deactivate or
restrict the transmission of cookies by changing the
settings in your web browser. Cookies that are already
stored can be deleted at any time. This can also be done
automatically. If cookies are deactivated for our
website, it may be the case that not all of the websites
functions can be used in full.
</p>
<h2>SSL encryption</h2>
<p>
Our website uses SSL encryption for security reasons and to
protect the transmission of confidential information,
for example enquiries you send to us as operators of
the website. You can recognise an encrypted connection
when the browsers address line changes from
<code>http://</code> to <code>https://</code> and a padlock
appears in your web browser.
</p>
<p>
If SSL encryption is activated, the data you transmit to us
cannot be read by third parties.
</p>
<h2>Rights of the data subject</h2>
<p>
With regard to the processing of your personal
data, you as a data subject are entitled to the
following rights pursuant to Art. 15 et seq. GDPR:
</p>
<ul>
<li>
You can request information as to whether we process
your personal data. If this is the case, you have the
right to information about this personal data as well
as further information in connection with the
processing (Art. 15 GDPR). Please note that this
right of access may be restricted or excluded in
certain cases (cf. in particular Art. 10 BayDSG).
</li>
<li>
In the event that personal data about you is (no
longer) accurate or incomplete, you may request that
this data be corrected and, if necessary, completed
(Art. 16 GDPR).
</li>
<li>
If the legal requirements are met, you can demand that
your personal data be erased (Art. 17 GDPR) or that
the processing of this data be restricted (Art. 18
DSGVO). However, the right to erasure pursuant to
Art. 17 (1) and (2) GDPR does not apply, inter alia,
if the processing of personal data is necessary for the
performance of a task carried out in the public
interest or in the exercise of official authority
or in the exercise of official authority vested (Art.
17 para. 3 letter b GDPR).
</li>
<li>
If you have given your consent to the processing, you
have the right to withdrawal it at any time. The
withdrawal will only take effect in the future;
this means that the withdrawal does not affect the
lawfulness of the processing operations carried out
on the basis of the consent up to the withdrawal.
</li>
<li>
For reasons arising from your particular situation, you
may also object to the processing of your personal
data by us at any time (Art. 21 GDPR). If the legal
requirements are met, we will subsequently no longer
process your personal data.
</li>
<li>
Insofar as you have consented to the processing of your
personal data or have agreed to the performance of
the contract and the data processing is carried out
automated, you may be entitled to data portability
(Art. 20 GDPR).
</li>
<li>
You have the right to lodge a complaint to a
supervisory authority within the meaning of Art. 51
GDPR about the processing of your personal data. The
responsible supervisory authority for XXX
authorities is YYY.
</li>
</ul>
</div>
</div>
</div>
{{end}}

View File

@ -14,22 +14,19 @@ var templates map[string]*template.Template = map[string]*template.Template{}
type Page struct { type Page struct {
Title string Title string
Login *LoginPage Error string
Info string
FilterPresets map[string]interface{} FilterPresets map[string]interface{}
Infos map[string]interface{} Infos map[string]interface{}
Config map[string]interface{} Config map[string]interface{}
} }
type LoginPage struct {
Error string
Info string
}
func init() { func init() {
templatesDir = "./templates/" templatesDir = "./templates/"
base := template.Must(template.ParseFiles(templatesDir + "base.tmpl")) base := template.Must(template.ParseFiles(templatesDir + "base.tmpl"))
files := []string{ files := []string{
"home.tmpl", "404.tmpl", "login.tmpl", "home.tmpl", "404.tmpl", "login.tmpl",
"imprint.tmpl", "privacy.tmpl",
"monitoring/jobs.tmpl", "monitoring/jobs.tmpl",
"monitoring/job.tmpl", "monitoring/job.tmpl",
"monitoring/list.tmpl", "monitoring/list.tmpl",