aboutsummaryrefslogtreecommitdiff
path: root/dudle.rb
# coding: utf-8
############################################################################
# Copyright 2009-2019 Benjamin Kellermann                                  #
#                                                                          #
# This file is part of Dudle.                                              #
#                                                                          #
# Dudle is free software: you can redistribute it and/or modify it under   #
# the terms of the GNU Affero General Public License as published by       #
# the Free Software Foundation, either version 3 of the License, or        #
# (at your option) any later version.                                      #
#                                                                          #
# Dudle is distributed in the hope that it will be useful, but WITHOUT ANY #
# WARRANTY; without even the implied warranty of MERCHANTABILITY or        #
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public     #
# License for more details.                                                #
#                                                                          #
# You should have received a copy of the GNU Affero General Public License #
# along with dudle.  If not, see <http://www.gnu.org/licenses/>.           #
############################################################################

$KCODE = "u" if RUBY_VERSION < '1.9.0'
require "yaml"
require "cgi"

$cgi = CGI.new unless $cgi

require 'gettext'
require 'gettext/cgi'
include GetText
GetText.cgi=$cgi
GetText.output_charset = 'utf-8'
require "locale"

if File.exists?("data.yaml") && !File.stat("data.yaml").directory?
	$is_poll = true
	GetText.bindtextdomain("dudle", :path => Dir.pwd + "/../locale/")
else
	$is_poll = false
	GetText.bindtextdomain("dudle", :path => Dir.pwd + "/locale/")
end

$:.push("..")
require_relative "date_locale"

require_relative "html"
require_relative "poll"
require_relative "config_defaults"
require_relative "charset"

class Dudle
	attr_reader :html, :table, :urlsuffix, :css, :user_css, :title, :tab
	def is_poll?
		$is_poll
	end
	def tabs_to_html(active_tab)
		ret = "<div id='tabs'><ul id='tablist'>"
		@tabs.each{|tab,file|
			case file
			when _(active_tab)
				ret += "<li id='active_tab' class='active_tab' >&nbsp;#{tab}&nbsp;</li> "
			when ""
				ret += "<li class='separator_tab'></li>"
			else
				ret += "<li class='nonactive_tab' ><a href='#{@html.relative_dir}#{file}'>&nbsp;#{tab}&nbsp;</a></li> "
			end
		}
		ret += "</ul></div>"
		ret
	end

	def inittabs
		@tabs = []
		@tabs << [_("Home"),@basedir]
		if is_poll?
			@tabs << ["",""]
			@tabs << [_("Poll"),"."]
			@tabs << [_("History"),"history.cgi"]
			@tabs << ["",""]
			@configtabs = [
				[_("Edit Columns"),"edit_columns.cgi"],
				[_("Invite Participants"),"invite_participants.cgi"],
				[_("Access Control"),"access_control.cgi"],
				[_("Overview"),"overview.cgi"]
			]
			@tabs += @configtabs
			@tabs << [_("Delete Poll"),"delete_poll.cgi"]
			@tabs << ["",""]
		else
			@tabs << [_("Examples"),"example.cgi"]
			@tabs << [_("About"),"about.cgi"]
		end
		@tabs << [_("Customize"),"customize.cgi"]
		@tabtitle = @tabs.collect{|title,file| title if file == @tab}.compact[0]
	end
	def revision
		@requested_revision || VCS.revno
	end
	def breadcrumbs
		crumbs = $conf.breadcrumbs
		crumbs << "<a href='#{@basedir}'>" + _("Dudle Home") + "</a>"
		if is_poll?
			if @tab == "."
				crumbs << @title
			else
				crumbs << "<a href='.'>#{@title}</a>"
				crumbs << @tabtitle
			end
		else
			if @tab != "."
				crumbs << @tabtitle
			end
		end
		"<div id='breadcrumbs'><ul><li class='breadcrumb'>#{crumbs.join("</li><li class='breadcrumb'>")}</li></ul></div>"
	end

	def initialize(params = {:revision => nil, :title => nil, :hide_lang_chooser => nil, :relative_dir => "", :load_extensions => true})
		@requested_revision = params[:revision]
		@hide_lang_chooser = params[:hide_lang_chooser]
		@cgi = $cgi
		@tab = File.basename($0)
		@tab = "." if @tab == "index.cgi"

		if is_poll?
			# log last read access manually (no need to grep server logfiles)
			File.open("last_read_access","w").close unless @cgi.user_agent =~ $conf.bots
			@basedir = ".."
			inittabs
			@table = YAML::load(VCS.cat(self.revision, "data.yaml"))
			@urlsuffix = File.basename(File.expand_path("."))
			@title = @table.name


			configfiles = @configtabs.collect{|name,file| file}
			@is_config = configfiles.include?(@tab)
			@wizzardindex = configfiles.index(@tab) if @is_config

			@html = HTML.new("dudle - #{@title} - #{@tabtitle}",params[:relative_dir])
			@html.add_html_head('<meta name="robots" content="noindex, nofollow" />')
			@html.header["Cache-Control"] = "no-cache"
		else
			@basedir = "."
			inittabs
			@title = params[:title] || "dudle"
			@html = HTML.new(@title,params[:relative_dir])
		end



		@css = ["default", "classic", "print"].collect{|f| f + ".css"}
		if Dir.exists?("#{@basedir}/css/")
			Dir.open("#{@basedir}/css/").each{|f|
				if f =~ /\.css$/
					@css << "css/#{f}"
				end
			}
		end
		if $cgi.include?("css")
			@user_css = $cgi["css"]
			@html.add_cookie("css",@user_css,"/",Time.now + (1*60*60*24*365 * (@user_css == $conf.default_css ? -1 : 1 )))
		else
			@user_css = $cgi.cookies["css"][0]
			@user_css ||= $conf.default_css
		end

		if $cgi.user_agent =~ /.*MSIE [567]\..*/
			css = [@user_css]
		else
			css = @css
		end
		css.each{|href|
			@html.add_css("#{@basedir}/#{href}",href.scan(/([^\/]*)\.css/).flatten[0] ,href == @user_css)
		}

		@html << <<HEAD
<body><div id="top"></div>
HEAD
		$conf.header.each{|h| @html << h }

		@html << <<HEAD
#{breadcrumbs}
<div id='main'>
#{tabs_to_html(@tab)}
<div id='content'>
	<h1 id='polltitle'>#{CGI.escapeHTML(@title)}</h1>
HEAD


		###################
		# init extenisons #
		###################
		@extensions = []
		$d = self # FIXME: this is dirty, but extensions need to know table elem
		if Dir.exists?("#{@basedir}/extensions/") && params[:load_extensions]
			Dir.open("#{@basedir}/extensions/").sort.each{|f|
				if File.exists?("#{@basedir}/extensions/#{f}/main.rb")
					@extensions << f
					if File.exists?("#{@basedir}/extensions/#{f}/preload.rb")
						$current_ext_dir = f
						require "#{@basedir}/extensions/#{f}/preload"
					end
				end
			}
		end
	end

	def wizzard_nav
		ret = "<div id='wizzard_navigation'><table><tr>"
		[[_("Previous"),@wizzardindex == 0],
		 [_("Next"),@wizzardindex >= @configtabs.size()-2],
		 [_("Finish"),@wizzardindex == @configtabs.size()-1]].each{|button,disabled|
			ret += <<READY
				<td>
					<form method='post' action=''>
						<div>
							<input type='hidden' name='undo_revision' value='#{self.revision}' />
							<input type='submit' #{disabled ? "disabled='disabled'" : ""} name='#{button}' value='#{button}' />
						</div>
					</form>
				</td>
READY
		}
		ret += "</tr></table></div>"
	end

	def wizzard_redirect
		[[_("Previous"),@wizzardindex-1],
		 [_("Next"),@wizzardindex+1],
		 [_("Finish"),@configtabs.size()-1]].each{|action,linkindex|
			if $cgi.include?(action)
				@html.header["status"] = "REDIRECT"
				@html.header["Cache-Control"] = "no-cache"
				@html.header["Location"] = @configtabs[linkindex][1]
				@html << _("All changes were saved successfully.") + " <a href=\"#{@configtabs[linkindex][1]}\">" + _("Proceed!") + "</a>"
				out
				exit
			end
		}
	end

	def out
		@html << wizzard_nav if @is_config

		@html.add_cookie("lang",@cgi["lang"],"/",Time.now + (1*60*60*24*365)) if @cgi.include?("lang")
		@html << "</div>" # content
		@html << "<div id='languageChooser'><ul>"
		lang = [# sorted by native speakers according to English Wikipedia
			["es", "Español"],# 480 million native speakers (2018)
			["en", "English"],# 360–400 million (2006)
			["ar", "اَلْعَرَبِيَّة"],# 310 million, all varieties (2011–2016)
			["pt_BR", "Português brasileiro"],# 205 million (2011)
			["de", "Deutsch"],# 95 million (2014)
			["it", "Italiano"],# 90 million (2012)
			["fr", "Français"],# 76.8 million (2014)
			["nl", "Nederlands"],# 24 million (2016)
			["sw", "Kiswahili"],# 15 million (2012)
			["hu", "Magyar"],# 13 million (2002–2012)
			["sv", "Svenska"],# 10 million (2018)
			["cs", "Česky"],# 10.7 million (2015)
			["da", "Dansk"],# 5.5 million (2012)
			["fi", "Finnish"],# 5.4 million (2009–2012)
			["he", "עִבְרִית"],# 5 million (2017)
			["no", "Norsk"],# 4.32 million (2012)
			["ca", "Català"],# 4.1 million (2012)
			["gl", "Galego"],# 2.4 million (2012)
			["et", "Eesti"],# 1.1 million (2012)
			["eo", "Esperanto"]# estimated 1000 to several thousand (2016)
		]
		unless @hide_lang_chooser
			lang.each{|short,long|
				if short == GetText.locale.to_s
					@html << "<li class='lang'>#{long}</li>"
				else
					@html << "<li class='lang'><a href='?lang=#{short}'>#{long}</a></li>"
				end
			}
		end
		@html << "</ul></div>" # languageChooser

		@html << "</div>" # main
		$conf.footer.each{|f| @html << f }
		@extensions.each{|e|
			if File.exists?("#{@basedir}/extensions/#{e}/main.rb")
				$current_ext_dir = e
				require "#{@basedir}/extensions/#{e}/main"
			end
		}

		@html << "</body>"
		@html.out(@cgi)
	end

	def <<(htmlbodytext)
		@html << htmlbodytext
	end

end