• Publicity: Public Only All

cookie-consent-procs.tcl

Integration of the Cookie Consent Library into OpenACS The Cookie Consent Library is and Cookie Consent to be free and open sourced library for alerting users about the use of cookies on a website. It is designed to help you comply with the hideous EU Cookie Law and not make you want to kill yourself in the process. So we made it fast, free, and relatively painless. Details: https://cookieconsent.insites.com/ https://github.com/insites/cookieconsent/ This package integrates the Consent Plugin with OpenACS, in particular with OpenACS subsites.

This file defines the following Objects and Classes: ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i], ::cookieconsent::CookieConsent[i]

Location:
packages/cookie-consent/tcl/cookie-consent-procs.tcl
Created:
13 Dec 2017
Author:
Gustaf Neumann
CVS Identification:
$Id: cookie-consent-procs.tcl,v 1.12.2.18 2024/08/17 17:07:30 gustafn Exp $

Procedures in this file

Detailed information

Class ::cookieconsent::CookieConsent (public)

 ::nx::Class ::cookieconsent::CookieConsent[i]

Create the Class for configuring the cookie consent widget. This class requires nx from the next-scripting framework. https://next-scripting.org/xowiki/ which is automatically installed for XOTcl2 via https://openacs.org/xowiki/naviserver-openacs

Testcases:
No testcase defined.

cookieconsent::add_to_page (public)

 cookieconsent::add_to_page [ -version version ] object

Add the necessary CSS, JavaScript and CSP to the current page.

Switches:
-version (optional)
Parameters:
object (required)

Partial Call Graph (max 5 caller/called nodes):
%3 test_cookie_consent__setup cookie_consent__setup (test cookie-consent) cookieconsent::add_to_page cookieconsent::add_to_page test_cookie_consent__setup->cookieconsent::add_to_page cookieconsent::resource_info cookieconsent::resource_info (public) cookieconsent::add_to_page->cookieconsent::resource_info security::csp::require security::csp::require (public) cookieconsent::add_to_page->security::csp::require template::add_body_script template::add_body_script (public) cookieconsent::add_to_page->template::add_body_script template::head::add_css template::head::add_css (public) cookieconsent::add_to_page->template::head::add_css template::head::add_javascript template::head::add_javascript (public) cookieconsent::add_to_page->template::head::add_javascript cookieconsent::initialize_widget cookieconsent::initialize_widget (public) cookieconsent::initialize_widget->cookieconsent::add_to_page

Testcases:
cookie_consent__setup

cookieconsent::initialize_widget (public)

 cookieconsent::initialize_widget [ -subsite_id subsite_id ]

Initialize a cookie-consent widget.

Switches:
-subsite_id (optional)

Partial Call Graph (max 5 caller/called nodes):
%3 test_cookie_consent__setup cookie_consent__setup (test cookie-consent) cookieconsent::initialize_widget cookieconsent::initialize_widget test_cookie_consent__setup->cookieconsent::initialize_widget ad_conn ad_conn (public) cookieconsent::initialize_widget->ad_conn ad_get_cookie ad_get_cookie (public) cookieconsent::initialize_widget->ad_get_cookie cookieconsent::add_to_page cookieconsent::add_to_page (public) cookieconsent::initialize_widget->cookieconsent::add_to_page cookieconsent::get_relevant_subsite cookieconsent::get_relevant_subsite (private) cookieconsent::initialize_widget->cookieconsent::get_relevant_subsite parameter::get parameter::get (public) cookieconsent::initialize_widget->parameter::get callback::subsite::page_plugin::impl::cookie-consent callback::subsite::page_plugin::impl::cookie-consent (private) callback::subsite::page_plugin::impl::cookie-consent->cookieconsent::initialize_widget

Testcases:
cookie_consent__setup

cookieconsent::reset_cookie (public)

 cookieconsent::reset_cookie [ -subsite_id subsite_id ]

Reset the consent cookie.

Switches:
-subsite_id (optional)

Partial Call Graph (max 5 caller/called nodes):
%3 test_cookie_consent__setup cookie_consent__setup (test cookie-consent) cookieconsent::reset_cookie cookieconsent::reset_cookie test_cookie_consent__setup->cookieconsent::reset_cookie ad_unset_cookie ad_unset_cookie (public) cookieconsent::reset_cookie->ad_unset_cookie cookieconsent::get_relevant_subsite cookieconsent::get_relevant_subsite (private) cookieconsent::reset_cookie->cookieconsent::get_relevant_subsite

Testcases:
cookie_consent__setup

cookieconsent::resource_info (public)

 cookieconsent::resource_info [ -version version ]

Get information about available version(s) of the cookieconsent packages, either from the local filesystem, or from CDN.

Switches:
-version (optional)
Returns:
dict containing resourceDir, resourceName, cdn, cdnHost, prefix, cssFiles, jsFiles and extraFiles.

Partial Call Graph (max 5 caller/called nodes):
%3 test_cookie_consent__setup cookie_consent__setup (test cookie-consent) cookieconsent::resource_info cookieconsent::resource_info test_cookie_consent__setup->cookieconsent::resource_info acs_package_root_dir acs_package_root_dir (public) cookieconsent::resource_info->acs_package_root_dir parameter::get_global_value parameter::get_global_value (public) cookieconsent::resource_info->parameter::get_global_value cookieconsent::add_to_page cookieconsent::add_to_page (public) cookieconsent::add_to_page->cookieconsent::resource_info packages/cookie-consent/www/sitewide-admin/download.tcl packages/cookie-consent/ www/sitewide-admin/download.tcl packages/cookie-consent/www/sitewide-admin/download.tcl->cookieconsent::resource_info packages/cookie-consent/www/sitewide-admin/index.tcl packages/cookie-consent/ www/sitewide-admin/index.tcl packages/cookie-consent/www/sitewide-admin/index.tcl->cookieconsent::resource_info

Testcases:
cookie_consent__setup
[ hide source ] | [ make this the default ]

Content File Source

ad_library {

    Integration of the Cookie Consent Library into OpenACS

    The Cookie Consent Library is and Cookie Consent to be free and
    open sourced library for alerting users about the use of
    cookies on a website.  It is designed to help you comply with the
    hideous EU Cookie Law and not make you want to kill yourself in
    the process. So we made it fast, free, and relatively painless.

    Details:
    https://cookieconsent.insites.com/
    https://github.com/insites/cookieconsent/

    This package integrates the Consent Plugin with OpenACS,
    in particular with OpenACS subsites.

    @author Gustaf Neumann
    @creation-date 13 Dec 2017
    @cvs-id $Id: cookie-consent-procs.tcl,v 1.12.2.18 2024/08/17 17:07:30 gustafn Exp $
}

namespace eval ::cookieconsent {
    variable parameter_info
    #
    # It is possible to configure the version of the cookie consent
    # widget also via NaviServer config file:
    #
    #   ns_section ns/server/${server}/acs/cookie-consent
    #      ns_param Version                     3.1.1

    set parameter_info {
        package_key cookie-consent
        parameter_name Version
        default_value 3.1.1
    }

    ad_proc -private get_relevant_subsite {} {
    } {
        set dict [security::get_register_subsite]
        if {![dict exists $dict subsite_id]} {
            set host_node_id [dict get $dict host_node_id]
            if {$host_node_id == 0} {
                #
                # Provide compatibility with older versions of
                # get_register_subsite, not returning the
                # host_node_id. In such cases, we get the host_node_id
                # via the URL
                #
                set node_info [site_node::get_from_url -url [dict get $dict url]]
                set host_node_id [dict get $node_info node_id]
            }
            set subsite_id [site_node::get_object_id -node_id $host_node_id]
        } else {
            set subsite_id [dict get $dict subsite_id]
        }
        return $subsite_id
    }

    d_proc reset_cookie {
        {-subsite_id ""}
    } {

        Reset the consent cookie.

    } {
        if {$subsite_id eq ""} {
            set subsite_id [get_relevant_subsite]
        }
        ad_unset_cookie "cookieconsent_status-$subsite_id"
    }

    nx::Class create CookieConsent {
        #
        # Create the Class for configuring the cookie consent widget.
        # This class requires nx from the next-scripting framework.
        #
        #     https://next-scripting.org/xowiki/
        #
        # which is automatically installed for XOTcl2 via
        # https://openacs.org/xowiki/naviserver-openacs
        #
        :property {position             pushdown};# bottom|top|pushdown|left|right
        :property {layout               block}   ;# block|classic|edgeless|wire
        :property {palette              default} ;# default|oacs|honeybee|mono|neon|corporate
        :property {learn-more-link      https://cookiesandyou.com/}
        :property {default-palette      {popup {text #fff background #004570} button {text #000 background #f1d600}}}
        :property {expiryDays:integer   365}

        :property {compliance-type      inform}  ;# inform|opt-out|opt-in
        :property {message-text        "#cookie-consent.message#"}
        :property {dismiss-button-text "#cookie-consent.dismiss-button-text#"}
        :property {policy-link-text    "#cookie-consent.policy-link-text#"}

        :property {subsite_id:required}

        :public method render_js {} {
            #
            # Perform the actual rendering of the cookie consent widget.
            #

            set static false
            if {${:position} eq "pushdown"} {
                set position top
                set static true
            } elseif  {${:position} in {"left" "right"}} {
                set position bottom-${:position}
            } else {
                set position ${:position}
            }

            #
            # Set up a dictionary for the palette with common
            # settings:
            #
            set d {popup {text #fff} button {text #000}}

            #
            # Update the default palette based on the value of the
            # passed-in palette.
            #
            switch ${:palette} {
                oacs {
                    dict set d popup background \#004570
                    dict set d button background \#f1d600
                }
                honeybee {
                    dict set d popup background \#000
                    dict set d button background \#f1d600
                }
                mono {
                    dict set d popup background \#237afc
                    dict set d button background transparent
                    dict set d button text \#fff
                    dict set d button border \#fff
                }
                neon {
                    dict set d popup background \#1d8a8a
                    dict set d button background \#62ffaa
                }
                corporate {
                    dict set d popup background \#edeff5
                    dict set d popup text \#838391
                    dict set d button background \#4b81e8
                }
                default {
                    set d ${:default-palette}
                }
            }

            #
            # We have to juggle the colors depending on the layout
            #
            set buttonBackground [dict get $d button background]
            set buttonTextColor  [dict get $d button text]
            if {[dict exists $d button border]} {
                set buttonBorder [dict get $d button border]
            } else {
                set buttonBorder $buttonBackground
            }
            switch ${:layout} {
                block    -
                classic  -
                edgeless {set theme ${:layout}}
                wire     {
                    set theme block
                    set buttonBackground transparent
                    set buttonTextColor  [dict get $d button background]
                }
            }

            #
            # Use different cookies dependent on the subsite
            #
            set cookie_name "cookieconsent_status-${:subsite_id}"

            set js [subst {
                window.addEventListener("load", function(){
                    window.cookieconsent.initialise({
                        "palette": {
                            "popup": {
                                "background""[dict get $d popup background]",
                                "text":       "[dict get $d popup text]",
                            },
                            "button": {
                                "background""$buttonBackground",
                                "border":     "$buttonBorder",
                                "text":       "$buttonTextColor"
                            }
                        },
                        "cookie": {
                            "name":       "$cookie_name",
                            "path":       "/",
                            "domain":     "",
                            "samesite":   "lax",
                            "expiryDays""${:expiryDays}"
                        },
                        "theme":    "$theme",
                        "position""$position",
                        "static":   $static,
                        "content": {
                            "message""[lang::util::localize ${:message-text}]",
                            "dismiss""[lang::util::localize ${:dismiss-button-text}]",
                            "link":    "[lang::util::localize ${:policy-link-text}]",
                            "href":    "${:learn-more-link}",
                            "header":  "Cookies used on the website!",
                            "deny":    "Decline",
                            "allow":   "Allow cookies"
                        }
                    })});
            }]
            return $js
        }
    }

    d_proc initialize_widget {
        {-subsite_id ""}
    } {

        Initialize a cookie-consent widget.

    } {
        if {![ns_conn isconnected]} {
            #
            # If the connection is already closed, do nothing.
            #
            return
        }

        if {$subsite_id eq ""} {
            set subsite_id [get_relevant_subsite]
        }

        set enabled_p [parameter::get \
                           -package_id $subsite_id \
                           -parameter CookieConsentEnabled \
                           -default 0]
        #
        # Just do real initialization, when the cookie is NOT set.
        # When more complex interactions are defined, this has to be
        # reconsidered.
        #
        set cookie_set [ad_get_cookie "cookieconsent_status-$subsite_id" ""]

        if {$enabled_p && $cookie_set eq "" && ![ad_conn bot_p]} {
            #
            # Create an instance of the consent widget class from all configuration options
            #
            foreach {param default} {
                ExpiryDays     365
                Layout         block
                Palette        oacs
                Position       bottom
                LearnMoreLink  https://cookiesandyou.com/
                DefaultPalette "popup {text #fff background #004570} button {text #000 background #f1d600}"
            } {
                set p($param) [parameter::get \
                                  -package_id $subsite_id \
                                  -parameter CookieConsent$param \
                                  -default $default]
            }

            set c [CookieConsent new \
                       -subsite_id      $subsite_id \
                       -expiryDays      $p(ExpiryDays) \
                       -position        $p(Position) \
                       -palette         $p(Palette) \
                       -layout          $p(Layout) \
                       -learn-more-link $p(LearnMoreLink) \
                       -default-palette $p(DefaultPalette) \
                      ]
            #
            # ... and add it to the page
            #
            add_to_page -version "" $c
            $c destroy
        }
    }


    d_proc resource_info {
        {-version ""}
    } {

        Get information about available version(s) of the
        cookieconsent packages, either from the local filesystem, or
        from CDN.

        @return dict containing resourceDir, resourceName, cdn,
                cdnHost, prefix, cssFiles, jsFiles and extraFiles.
    } {
        variable parameter_info
        #
        # If no version of the cookie consent library was specified,
        # use the name-spaced variable as default.
        #
        if {$version eq ""} {
            dict with parameter_info {
                set version [::parameter::get_global_value \
                                 -package_key $package_key \
                                 -parameter $parameter_name \
                                 -default $default_value]
            }
        }

        #
        # Provide paths for loading either via resources or CDN
        #
        #   "resourceDir" is the absolute path in the filesystem
        #   "versionSegment" is the version-specific element both in the
        #                URL and in the filesystem.

        set resourceDir [acs_package_root_dir cookie-consent/www/resources]
        set cdn         //cdnjs.cloudflare.com/ajax/libs/cookieconsent2

        #
        # If the resources are not available locally, these will be
        # loaded via CDN and the CDN host is set (necessary for CSP).
        # The returned "prefix" indicates the place, from where the
        # resource will be loaded.
        #
        if {[file exists $resourceDir/$version]} {
            set prefix /resources/cookie-consent/$version/
            set cdnHost ""
        } else {
            set prefix $cdn/$version/
            set cdnHost cdnjs.cloudflare.com
        }
        lappend result \
            resourceName "Cookie Consent Widget" \
            resourceDir $resourceDir \
            cdn $cdn \
            cdnHost $cdnHost \
            prefix $prefix \
            cssFiles {cookieconsent.min.css} \
            jsFiles  {cookieconsent.min.js} \
            extraFiles {} \
            versionCheckAPI {cdn cdnjs library cookieconsent2 count 5} \
            vulnerabilityCheck {service snyk library cookieconsent2} \
            parameterInfo $parameter_info \
            configuredVersion $version

        return $result
    }


    d_proc add_to_page {
        {-version ""}
        object
    } {
        Add the necessary CSS, JavaScript and CSP to the current
        page.
    } {
        set resource_info [resource_info -version $version]

        if {[dict exists $resource_info cdnHost] && [dict get $resource_info cdnHost] ne ""} {
            security::csp::require script-src [dict get $resource_info cdnHost]
            security::csp::require style-src [dict get $resource_info cdnHost]
        }
        set prefix [dict get $resource_info prefix]

        foreach cssFile [dict get $resource_info cssFiles] {
            template::head::add_css -href $prefix/$cssFile
        }
        foreach jsFile [dict get $resource_info jsFiles] {
            template::head::add_javascript -src $prefix/$jsFile
        }

        ::template::add_body_script -script [$object render_js]
    }

}

# Local variables:
#    mode: tcl
#    tcl-indent-level: 4
#    indent-tabs-mode: nil
# End: