View source with raw comments or as raw
    1/*  Part of ClioPatria SeRQL and SPARQL server
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@cs.vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (C): 2004-2010, University of Amsterdam,
    7			      VU University Amsterdam
    8
    9    This program is free software; you can redistribute it and/o<r
   10    modify it under the terms of the GNU General Public License
   11    as published by the Free Software Foundation; either version 2
   12    of the License, or (at your option) any later version.
   13
   14    This program is distributed in the hope that it will be useful,
   15    but WITHOUT ANY WARRANTY; without even the implied warranty of
   16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17    GNU General Public License for more details.
   18
   19    You should have received a copy of the GNU General Public
   20    License along with this library; if not, write to the Free Software
   21    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22
   23    As a special exception, if you link this library with other files,
   24    compiled with a Free Software compiler, to produce an executable, this
   25    library does not by itself cause the resulting executable to be covered
   26    by the GNU General Public License. This exception does not however
   27    invalidate any other reasons why the executable file might be covered by
   28    the GNU General Public License.
   29*/
   30
   31:- module(cpa_admin,
   32	  [ change_password_form//1
   33	  ]).   34:- use_module(user(user_db)).   35:- use_module(library(http/http_parameters)).   36:- use_module(library(http/http_session)).   37:- use_module(library(http/html_write)).   38:- use_module(library(http/html_head)).   39:- use_module(library(http/mimetype)).   40:- use_module(library(http/http_dispatch)).   41:- use_module(library(url)).   42:- use_module(library(debug)).   43:- use_module(library(lists)).   44:- use_module(library(option)).   45:- use_module(library(http_settings)).

ClioPatria administrative interface

This module provides HTTP services to perform administrative actions.

To be done
-
Ideally, this module should be split into an api-part, a component-part and the actual pages. This also implies that the current `action'-operations must (optionally) return machine-friendly results. */
   58:- http_handler(cliopatria('admin/listUsers'),		   list_users,		    []).   59:- http_handler(cliopatria('admin/form/createAdmin'),	   create_admin,	    []).   60:- http_handler(cliopatria('admin/form/addUser'),	   add_user_form,	    []).   61:- http_handler(cliopatria('admin/form/addOpenIDServer'),  add_openid_server_form,  []).   62:- http_handler(cliopatria('admin/addUser'),		   add_user,		    []).   63:- http_handler(cliopatria('admin/selfRegister'),	   self_register,	    []).   64:- http_handler(cliopatria('admin/addOpenIDServer'),	   add_openid_server,	    []).   65:- http_handler(cliopatria('admin/form/editUser'),	   edit_user_form,	    []).   66:- http_handler(cliopatria('admin/editUser'),		   edit_user,		    []).   67:- http_handler(cliopatria('admin/delUser'),		   del_user,		    []).   68:- http_handler(cliopatria('admin/form/editOpenIDServer'), edit_openid_server_form, []).   69:- http_handler(cliopatria('admin/editOpenIDServer'),	   edit_openid_server,	    []).   70:- http_handler(cliopatria('admin/delOpenIDServer'),	   del_openid_server,	    []).   71:- http_handler(cliopatria('admin/form/changePassword'),   change_password_form,    []).   72:- http_handler(cliopatria('admin/changePassword'),	   change_password,	    []).   73:- http_handler(cliopatria('user/form/login'),		   login_form,		    []).   74:- http_handler(cliopatria('user/login'),		   user_login,		    []).   75:- http_handler(cliopatria('user/logout'),		   user_logout,		    []).   76:- http_handler(cliopatria('admin/settings'),		   settings,		    []).   77:- http_handler(cliopatria('admin/save_settings'),	   save_settings,	    []).
 list_users(+Request)
HTTP Handler listing registered users.
   83list_users(_Request) :-
   84	authorized(admin(list_users)),
   85	if_allowed(admin(user(edit)),   [edit(true)], UserOptions),
   86	if_allowed(admin(openid(edit)), [edit(true)], OpenIDOptions),
   87	reply_html_page(cliopatria(default),
   88			title('Users'),
   89			[ h1('Users'),
   90			  \user_table(UserOptions),
   91			  p(\action(location_by_id(add_user_form), 'Add user')),
   92			  h1('OpenID servers'),
   93			  \openid_server_table(OpenIDOptions),
   94			  p(\action(location_by_id(add_openid_server_form), 'Add OpenID server'))
   95			]).
   96
   97if_allowed(Token, Options, Options) :-
   98	logged_on(User, anonymous),
   99	catch(check_permission(User, Token), _, fail), !.
  100if_allowed(_, _, []).
 user_table(+Options)//
HTML component generating a table of registered users.
  106user_table(Options) -->
  107	{ setof(U, current_user(U), Users)
  108	},
  109	html([ table([ class(block)
  110		     ],
  111		     [ tr([ th('UserID'),
  112			    th('RealName'),
  113			    th('On since'),
  114			    th('Idle')
  115			  ])
  116		     | \list_users(Users, Options)
  117		     ])
  118	     ]).
  119
  120list_users([], _) -->
  121	[].
  122list_users([User|T], Options) -->
  123	{ user_property(User, realname(Name)),
  124	  findall(Idle-Login,
  125		  user_property(User, connection(Login, Idle)),
  126		  Pairs0),
  127	  keysort(Pairs0, Pairs),
  128	  (   Pairs == []
  129	  ->  OnLine = (-)
  130	  ;   length(Pairs, N),
  131	      Pairs = [Idle-Login|_],
  132	      OnLine = online(Login, Idle, N)
  133	  )
  134	},
  135	html(tr([ td(User),
  136		  td(Name),
  137		  td(\on_since(OnLine)),
  138		  td(\idle(OnLine)),
  139		  \edit_user_button(User, Options)
  140		])),
  141	list_users(T, Options).
  142
  143edit_user_button(User, Options) -->
  144	{ option(edit(true), Options) }, !,
  145	html(td(a(href(location_by_id(edit_user_form)+'?user='+encode(User)), 'Edit'))).
  146edit_user_button(_, _) -->
  147	[].
  148
  149on_since(online(Login, _Idle, _Connections)) --> !,
  150	{ format_time(string(Date), '%+', Login)
  151	},
  152	html(Date).
  153on_since(_) -->
  154	html(-).
  155
  156idle(online(_Login, Idle, _Connections)) -->
  157	{ mmss_duration(Idle, String)
  158	},
  159	html(String).
  160idle(_) -->
  161	html(-).
  162
  163
  164mmss_duration(Time, String) :-		% Time in seconds
  165	Secs is round(Time),
  166	Hour is Secs // 3600,
  167	Min  is (Secs // 60) mod 60,
  168	Sec  is Secs mod 60,
  169	format(string(String), '~`0t~d~2|:~`0t~d~5|:~`0t~d~8|', [Hour, Min, Sec]).
  170
  171
  172
  173		 /*******************************
  174		 *	      ADD USERS		*
  175		 *******************************/
 create_admin(+Request)
Create the administrator login.
  181create_admin(_Request) :-
  182	(   current_user(_)
  183	->  throw(error(permission_error(create, user, admin),
  184			context(_, 'Already initialized')))
  185	;   true
  186	),
  187	reply_html_page(cliopatria(default),
  188			title('Create administrator'),
  189			[ h1(align(center), 'Create administrator'),
  190
  191			  p('No accounts are available on this server. \c
  192			  This form allows for creation of an administrative \c
  193			  account that can subsequently be used to create \c
  194			  new users.'),
  195
  196			  \new_user_form([ user(admin),
  197					   real_name('Administrator')
  198					 ])
  199			]).
 add_user_form(+Request)
Form to register a user.
  206add_user_form(_Request) :-
  207	authorized(admin(add_user)),
  208	reply_html_page(cliopatria(default),
  209			title('Add new user'),
  210			[ \new_user_form([])
  211			]).
  212
  213new_user_form(Options) -->
  214	{ (   option(user(User), Options)
  215	  ->  UserOptions = [value(User)],
  216	      PermUser = User
  217	  ;   UserOptions = [],
  218	      PermUser = (-)
  219	  )
  220	},
  221	html([ h1('Add new user'),
  222	       form([ action(location_by_id(add_user)),
  223		      method('POST')
  224		    ],
  225		    table([ class((form))
  226			  ],
  227			  [ \realname(Options),
  228			    \input(user,     'Login',
  229				   UserOptions),
  230			    \input(pwd1,     'Password',
  231				   [type(password)]),
  232			    \input(pwd2,     'Retype',
  233				   [type(password)]),
  234			    \permissions(PermUser),
  235			    tr(class(buttons),
  236			       td([ colspan(2),
  237				    align(right)
  238				  ],
  239				  input([ type(submit),
  240					  value('Create')
  241					])))
  242			  ]))
  243	     ]).
  244
  245
  246input(Name, Label, Options) -->
  247	html(tr([ th(align(right), Label),
  248		  td(input([name(Name),size(40)|Options]))
  249		])).
  250
  251%	Only provide a realname field if this is not already given. This
  252%	is because firefox determines the login user from the text field
  253%	immediately above the password entry. Other   browsers may do it
  254%	different, so only having one text-field  is probably the savest
  255%	solution.
  256
  257realname(Options) -->
  258	{ option(real_name(RealName), Options) }, !,
  259	hidden(realname, RealName).
  260realname(_Options) -->
  261	input(realname, 'Realname', []).
 add_user(+Request)
API to register a new user. The current user must have administrative rights or the user-database must be empty.
  269add_user(Request) :-
  270	(   \+ current_user(_)
  271	->  FirstUser = true
  272	;   authorized(admin(add_user))
  273	),
  274	http_parameters(Request,
  275			[ user(User),
  276			  realname(RealName),
  277			  pwd1(Password),
  278			  pwd2(Retype),
  279			  read(Read),
  280			  write(Write),
  281			  admin(Admin)
  282			],
  283			[ attribute_declarations(attribute_decl)
  284			]),
  285	(   current_user(User)
  286	->  throw(error(permission_error(create, user, User),
  287			context(_, 'Already present')))
  288	;   true
  289	),
  290	(   Password == Retype
  291	->  true
  292	;   throw(password_mismatch)
  293	),
  294	password_hash(Password, Hash),
  295	phrase(allow(Read, Write, Admin), Allow),
  296	user_add(User,
  297		 [ realname(RealName),
  298		   password(Hash),
  299		   allow(Allow)
  300		 ]),
  301	(   FirstUser == true
  302	->  user_add(anonymous,
  303		     [ realname('Define rights for not-logged in users'),
  304		       allow([read(_,_)])
  305		     ]),
  306	    reply_login([user(User), password(Password)])
  307	;   list_users(Request)
  308	).
 self_register(Request)
Self-register and login a new user if cliopatria:enable_self_register is set to true. Users are registered with full read and limited (annotate-only) write access.

Returns a HTTP 403 forbidden error if:

  321self_register(Request) :-
  322	http_location_by_id(self_register, MyUrl),
  323	(   \+ setting(cliopatria:enable_self_register, true)
  324	->  throw(http_reply(forbidden(MyUrl)))
  325	;   true
  326	),
  327	http_parameters(Request,
  328			[ user(User),
  329			  realname(RealName),
  330			  password(Password)
  331			],
  332			[ attribute_declarations(attribute_decl)
  333			]),
  334	(   current_user(User)
  335	->  throw(http_reply(forbidden(MyUrl)))
  336	;   true
  337	),
  338	password_hash(Password, Hash),
  339	Allow = [ read(_,_), write(_,annotate) ],
  340	user_add(User, [realname(RealName), password(Hash), allow(Allow)]),
  341	reply_login([user(User), password(Password)]).
 edit_user_form(+Request)
Form to edit user properties
  348edit_user_form(Request) :-
  349	authorized(admin(user(edit))),
  350	http_parameters(Request,
  351			[ user(User)
  352			],
  353			[ attribute_declarations(attribute_decl)
  354			]),
  355
  356	reply_html_page(cliopatria(default),
  357			title('Edit user'),
  358			\edit_user_form(User)).
 edit_user_form(+User)//
HTML component to edit the properties of User.
  364edit_user_form(User) -->
  365	{ user_property(User, realname(RealName))
  366	},
  367	html([ h1(['Edit user ', User, ' (', RealName, ')']),
  368
  369	       form([ action(location_by_id(edit_user)),
  370		      method('POST')
  371		    ],
  372		    [ \hidden(user, User),
  373		      table([ class((form))
  374			    ],
  375			    [ \user_property(User, realname, 'Real name', []),
  376			      \permissions(User),
  377			      tr(class(buttons),
  378				 td([ colspan(2),
  379				      align(right)
  380				    ],
  381				    input([ type(submit),
  382					    value('Modify')
  383					  ])))
  384			    ])
  385		    ]),
  386
  387	       p(\action(location_by_id(del_user)+'?user='+encode(User),
  388			 [ 'Delete user ', b(User), ' (', i(RealName), ')' ]))
  389	     ]).
  390
  391user_property(User, Name, Label, Options) -->
  392	{  Term =.. [Name, Value],
  393	   user_property(User, Term)
  394	-> O2 = [value(Value)|Options]
  395	;  O2 = Options
  396	},
  397	html(tr([ th(class(p_name), Label),
  398		  td(input([name(Name),size(40)|O2]))
  399		])).
  400
  401permissions(User) -->
  402	html(tr([ th(class(p_name), 'Permissions'),
  403		  td([ \permission_checkbox(User, read,  'Read'),
  404		       \permission_checkbox(User, write, 'Write'),
  405		       \permission_checkbox(User, admin, 'Admin')
  406		     ])
  407		])).
  408
  409permission_checkbox(User, Name, Label) -->
  410	{ (   User \== (-),
  411	      (	  user_property(User, allow(Actions))
  412	      ->  true
  413	      ;	  openid_server_property(User, allow(Actions))
  414	      ),
  415	      pterm(Name, Action),
  416	      memberchk(Action, Actions)
  417	  ->  Opts = [checked]
  418	  ;   def_user_permissions(User, DefPermissions),
  419	      memberchk(Name, DefPermissions)
  420	  ->  Opts = [checked]
  421	  ;   Opts = []
  422	  )
  423	},
  424	html([ input([ type(checkbox),
  425		       name(Name)
  426		     | Opts
  427		     ]),
  428	       Label
  429	     ]).
  430
  431def_user_permissions(-, [read]).
  432def_user_permissions(admin, [read, write, admin]).
 edit_user(Request)
Handle reply from edit user form.
  439edit_user(Request) :-
  440	authorized(admin(user(edit))),
  441	http_parameters(Request,
  442			[ user(User),
  443			  realname(RealName,
  444				   [ optional(true),
  445				     length > 2,
  446				     description('Comment on user identifier-name')
  447				   ]),
  448			  read(Read),
  449			  write(Write),
  450			  admin(Admin)
  451			],
  452			[ attribute_declarations(attribute_decl)
  453			]),
  454	modify_user(User, realname(RealName)),
  455	modify_permissions(User, Read, Write, Admin),
  456	list_users(Request).
  457
  458
  459modify_user(User, Property) :-
  460	Property =.. [_Name|Value],
  461	(   (   var(Value)
  462	    ;	Value == ''
  463	    )
  464	->  true
  465	;   set_user_property(User, Property)
  466	).
  467
  468modify_permissions(User, Read, Write, Admin) :-
  469	phrase(allow(Read, Write, Admin), Allow),
  470	set_user_property(User, allow(Allow)).
  471
  472allow(Read, Write, Admin) -->
  473	allow(read, Read),
  474	allow(write, Write),
  475	allow(admin, Admin).
  476
  477allow(Access, on) -->
  478	{ pterm(Access, Allow)
  479	}, !,
  480	[ Allow
  481	].
  482allow(_Access, off) --> !,
  483	[].
  484
  485pterm(read,  read(_Repositiory, _Action)).
  486pterm(write, write(_Repositiory, _Action)).
  487pterm(admin, admin(_Action)).
 del_user(+Request)
Delete a user
  494del_user(Request) :- !,
  495	authorized(admin(del_user)),
  496	http_parameters(Request,
  497			[ user(User)
  498			],
  499			[ attribute_declarations(attribute_decl)
  500			]),
  501	(   User == admin
  502	->  throw(error(permission_error(delete, user, User), _))
  503	;   true
  504	),
  505	user_del(User),
  506	list_users(Request).
 change_password_form(+Request)
Allow user to change the password
  513change_password_form(_Request) :-
  514	logged_on(User), !,
  515	user_property(User, realname(RealName)),
  516	reply_html_page(cliopatria(default),
  517			title('Change password'),
  518			[ h1(['Change password for ', User, ' (', RealName, ')']),
  519
  520			  \change_password_form(User)
  521			]).
  522change_password_form(_Request) :-
  523	throw(error(context_error(not_logged_in), _)).
 change_password_form(+UserID)//
HTML component that shows a form for changing the password for UserID.
  531change_password_form(User) -->
  532	html(form([ action(location_by_id(change_password)),
  533		    method('POST')
  534		  ],
  535		  [ table([ id('change-password-form'),
  536			    class(form)
  537			  ],
  538			  [ \user_or_old(User),
  539			    \input(pwd1,     'New Password',
  540				   [type(password)]),
  541			    \input(pwd2,     'Retype',
  542				   [type(password)]),
  543			    tr(class(buttons),
  544			       td([ align(right),
  545				    colspan(2)
  546				  ],
  547				  input([ type(submit),
  548					  value('Change password')
  549					])))
  550			  ])
  551		  ])).
  552
  553user_or_old(admin) --> !,
  554	input(user, 'User', []).
  555user_or_old(_) -->
  556	input(pwd0, 'Old password', [type(password)]).
 change_password(+Request)
HTTP handler to change the password. The user must be logged on.
  563change_password(Request) :-
  564	logged_on(Login), !,
  565	http_parameters(Request,
  566			[ user(User,     [ optional(true),
  567					   description('User identifier-name')
  568					 ]),
  569			  pwd0(Password, [ optional(true),
  570					   description('Current password')
  571					 ]),
  572			  pwd1(New),
  573			  pwd2(Retype)
  574			],
  575			[ attribute_declarations(attribute_decl)
  576			]),
  577	(   Login == admin
  578	->  (   current_user(User)
  579	    ->	true
  580	    ;	throw(error(existence_error(user, User), _))
  581	    )
  582	;   Login = User,
  583	    validate_password(User, Password)
  584	),
  585	(   New == Retype
  586	->  true
  587	;   throw(password_mismatch)
  588	),
  589	password_hash(New, Hash),
  590	set_user_property(User, password(Hash)),
  591	reply_html_page(cliopatria(default),
  592			'Password changed',
  593			[ h1(align(center), 'Password changed'),
  594			  p([ 'Your password has been changed successfully' ])
  595			]).
  596change_password(_Request) :-
  597	throw(error(context_error(not_logged_in), _)).
  598
  599
  600
  601		 /*******************************
  602		 *	       LOGIN		*
  603		 *******************************/
 login_form(+Request)
HTTP handler that presents a form to login.
  609login_form(_Request) :-
  610	reply_html_page(cliopatria(default),
  611			'Login',
  612			[ h1(align(center), 'Login'),
  613			  form([ action(location_by_id(user_login)),
  614				 method('POST')
  615			       ],
  616			       table([ tr([ th(align(right), 'User:'),
  617					    td(input([ name(user),
  618						       size(40)
  619						     ]))
  620					  ]),
  621				       tr([ th(align(right), 'Password:'),
  622					    td(input([ type(password),
  623						       name(password),
  624						       size(40)
  625						     ]))
  626					  ]),
  627				       tr([ td([ align(right), colspan(2) ],
  628					       input([ type(submit),
  629						       value('Login')
  630						     ]))
  631					  ])
  632				     ])
  633			      )
  634			]).
 user_login(+Request)
Handle user and password. If there is a parameter return_to or openid.return_to, reply using a redirect to the given URL. Otherwise display a welcome page.
  642user_login(Request) :- !,
  643	http_parameters(Request,
  644			[ user(User),
  645			  password(Password),
  646			  'openid.return_to'(ReturnTo, [optional(true)]),
  647			  'return_to'(ReturnTo, [optional(true)])
  648			],
  649			[ attribute_declarations(attribute_decl)
  650			]),
  651	(   var(ReturnTo)
  652	->  Extra = []
  653	;   uri_normalized(/, ReturnTo, PublicHost),
  654	    Extra = [ return_to(ReturnTo),
  655		      public_host(PublicHost)
  656		    ]
  657	),
  658	reply_login([ user(User),
  659		      password(Password)
  660		    | Extra
  661		    ]).
  662
  663
  664reply_login(Options) :-
  665	option(user(User), Options),
  666	option(password(Password), Options),
  667	validate_password(User, Password), !,
  668	login(User, Options),
  669	(   option(return_to(ReturnTo), Options)
  670	->  throw(http_reply(moved_temporary(ReturnTo)))
  671	;   reply_html_page(cliopatria(default),
  672			    title('Login ok'),
  673			    h1(align(center), ['Welcome ', User]))
  674	).
  675reply_login(_) :-
  676	reply_html_page(cliopatria(default),
  677			title('Login failed'),
  678			[ h1('Login failed'),
  679			  p(['Password incorrect'])
  680			]).
 user_logout(+Request)
Logout the current user
  686user_logout(_Request) :-
  687	logged_on(User), !,
  688	logout(User),
  689	reply_html_page(cliopatria(default),
  690			title('Logout'),
  691			h1(align(center), ['Logged out ', User])).
  692user_logout(_Request) :-
  693	reply_html_page(cliopatria(default),
  694			title('Logout'),
  695			[ h1(align(center), ['Not logged on']),
  696			  p(['Possibly you are logged out because the session ',
  697			     'has timed out.'])
  698			]).
 attribute_decl(+Param, -DeclObtions) is semidet
Provide reusable parameter declarations for calls to http_parameters/3.
  705attribute_decl(user,
  706	       [ description('User identifier-name'),
  707		 length > 1
  708	       ]).
  709attribute_decl(realname,
  710	       [ description('Comment on user identifier-name')
  711	       ]).
  712attribute_decl(description,
  713	       [ optional(true),
  714		 description('Descriptive text')
  715	       ]).
  716attribute_decl(password,
  717	       [ description('Password')
  718	       ]).
  719attribute_decl(pwd1,
  720	       [ length > 5,
  721		 description('Password')
  722	       ]).
  723attribute_decl(pwd2,
  724	       [ length > 5,
  725		 description('Re-typed password')
  726	       ]).
  727attribute_decl(openid_server,
  728	       [ description('URL of an OpenID server')
  729	       ]).
  730attribute_decl(read,
  731	       [ description('Provide read-only access to the RDF store')
  732	       | Options])   :- bool(off, Options).
  733attribute_decl(write,
  734	       [ description('Provide write access to the RDF store')
  735	       | Options])   :- bool(off, Options).
  736attribute_decl(admin,
  737	       [ description('Provide administrative rights')
  738	       | Options])   :- bool(off, Options).
  739
  740bool(Def,
  741     [ default(Def),
  742       oneof([on, off])
  743     ]).
  744
  745
  746		 /*******************************
  747		 *	    OPENID ADMIN	*
  748		 *******************************/
 add_openid_server_form(+Request)
Return an HTML page to add a new OpenID server.
  754add_openid_server_form(_Request) :-
  755	authorized(admin(add_openid_server)),
  756	reply_html_page(cliopatria(default),
  757			title('Add OpenID server'),
  758			[ \new_openid_form
  759			]).
 new_openid_form// is det
Present form to add a new OpenID provider.
  766new_openid_form -->
  767	html([ h1('Add new OpenID server'),
  768	       form([ action(location_by_id(add_openid_server)),
  769		      method('GET')
  770		    ],
  771		    table([ id('add-openid-server'),
  772			    class(form)
  773			  ],
  774			  [ \input(openid_server, 'Server homepage', []),
  775			    \input(openid_description, 'Server description',
  776				   []),
  777			    \permissions(-),
  778			    tr(class(buttons),
  779			       td([ colspan(2),
  780				    align(right)
  781				  ],
  782				  input([ type(submit),
  783					  value('Create')
  784					])))
  785			  ])),
  786	       p([ 'Use this form to define access rights for users of an ',
  787		   a(href('http://www.openid.net'), 'OpenID'), ' server. ',
  788		   'The special server ', code(*), ' specifies access for all OpenID servers. ',
  789		   'Here are some examples of servers:'
  790		 ]),
  791	       ul([ li(code('http://myopenid.com'))
  792		  ])
  793	     ]).
 add_openid_server(+Request)
Allow access from an OpenID server
  800add_openid_server(Request) :-
  801	authorized(admin(add_openid_server)),
  802	http_parameters(Request,
  803			[ openid_server(Server0,
  804					[ description('URL of the server to allow')]),
  805			  openid_description(Description,
  806					     [ optional(true),
  807					       description('Description of the server')
  808					     ]),
  809			  read(Read),
  810			  write(Write)
  811			],
  812			[ attribute_declarations(attribute_decl)
  813			]),
  814	phrase(allow(Read, Write, off), Allow),
  815	canonical_url(Server0, Server),
  816	Options = [ description(Description),
  817		    allow(Allow)
  818		  ],
  819	remove_optional(Options, Properties),
  820	openid_add_server(Server, Properties),
  821	list_users(Request).
  822
  823remove_optional([], []).
  824remove_optional([H|T0], [H|T]) :-
  825	arg(1, H, A),
  826	nonvar(A), !,
  827	remove_optional(T0, T).
  828remove_optional([_|T0], T) :-
  829	remove_optional(T0, T).
  830
  831
  832canonical_url(Var, Var) :-
  833	var(Var), !.
  834canonical_url(*, *) :- !.
  835canonical_url(URL0, URL) :-
  836	parse_url(URL0, Parts),
  837	parse_url(URL, Parts).
 edit_openid_server_form(+Request)
Form to edit user properties
  844edit_openid_server_form(Request) :-
  845	authorized(admin(openid(edit))),
  846	http_parameters(Request,
  847			[ openid_server(Server)
  848			],
  849			[ attribute_declarations(attribute_decl)
  850			]),
  851
  852	reply_html_page(cliopatria(default),
  853			title('Edit OpenID server'),
  854			\edit_openid_server_form(Server)).
  855
  856edit_openid_server_form(Server) -->
  857	html([ h1(['Edit OpenID server ', Server]),
  858
  859	       form([ action(location_by_id(edit_openid_server)),
  860		      method('GET')
  861		    ],
  862		    [ \hidden(openid_server, Server),
  863		      table([ class(form)
  864			    ],
  865			    [ \openid_property(Server, description, 'Description', []),
  866			      \permissions(Server),
  867			      tr(class(buttons),
  868				 td([ colspan(2),
  869				      align(right)
  870				    ],
  871				    input([ type(submit),
  872					    value('Modify')
  873					  ])))
  874			    ])
  875		    ]),
  876
  877	       p(\action(location_by_id(del_openid_server) +
  878			 '?openid_server=' + encode(Server),
  879			 [ 'Delete ', b(Server) ]))
  880	     ]).
  881
  882
  883openid_property(Server, Name, Label, Options) -->
  884	{  Term =.. [Name, Value],
  885	   openid_server_property(Server, Term)
  886	-> O2 = [value(Value)|Options]
  887	;  O2 = Options
  888	},
  889	html(tr([ th(align(right), Label),
  890		  td(input([name(Name),size(40)|O2]))
  891		])).
 openid_server_table(+Options)//
List registered openid servers
  898openid_server_table(Options) -->
  899	{ setof(S, openid_current_server(S), Servers), !
  900	},
  901	html([ table([ class(block)
  902		     ],
  903		     [ tr([ th('Server'),
  904			    th('Description')
  905			  ])
  906		     | \openid_list_servers(Servers, Options)
  907		     ])
  908	     ]).
  909openid_server_table(_) -->
  910	[].
  911
  912openid_list_servers([], _) -->
  913	[].
  914openid_list_servers([H|T], Options) -->
  915	openid_list_server(H, Options),
  916	openid_list_servers(T, Options).
  917
  918openid_list_server(Server, Options) -->
  919	html(tr([td(\openid_server(Server)),
  920		 td(\openid_field(Server, description)),
  921		 \edit_openid_button(Server, Options)
  922		])).
  923
  924edit_openid_button(Server, Options) -->
  925	{ option(edit(true), Options) }, !,
  926	html(td(a(href(location_by_id(edit_openid_server_form) +
  927		       '?openid_server='+encode(Server)
  928		      ), 'Edit'))).
  929edit_openid_button(_, _) --> [].
  930
  931
  932
  933openid_server(*) --> !,
  934	html(*).
  935openid_server(Server) -->
  936	html(a(href(Server), Server)).
  937
  938openid_field(Server, Field) -->
  939	{ Term =.. [Field, Value],
  940	  openid_server_property(Server, Term)
  941	}, !,
  942	html(Value).
  943openid_field(_, _) -->
  944	[].
 edit_openid_server(Request)
Handle reply from OpenID server form.
  951edit_openid_server(Request) :-
  952	authorized(admin(openid(edit))),
  953	http_parameters(Request,
  954			[ openid_server(Server),
  955			  description(Description),
  956			  read(Read),
  957			  write(Write),
  958			  admin(Admin)
  959			],
  960			[ attribute_declarations(attribute_decl)
  961			]),
  962	modify_openid(Server, description(Description)),
  963	openid_modify_permissions(Server, Read, Write, Admin),
  964	list_users(Request).
  965
  966
  967modify_openid(User, Property) :-
  968	Property =.. [_Name|Value],
  969	(   (   var(Value)
  970	    ;	Value == ''
  971	    )
  972	->  true
  973	;   openid_set_property(User, Property)
  974	).
  975
  976
  977openid_modify_permissions(Server, Read, Write, Admin) :-
  978	phrase(allow(Read, Write, Admin), Allow),
  979	openid_set_property(Server, allow(Allow)).
 del_openid_server(+Request)
Delete an OpenID Server
  986del_openid_server(Request) :- !,
  987	authorized(admin(openid(delete))),
  988	http_parameters(Request,
  989			[ openid_server(Server)
  990			],
  991			[ attribute_declarations(attribute_decl)
  992			]),
  993	openid_del_server(Server),
  994	list_users(Request).
  995
  996
  997		 /*******************************
  998		 *	       SETTINGS		*
  999		 *******************************/
 settings(+Request)
Show current settings. If user has administrative rights, allow editing the settings.
 1006settings(_Request) :-
 1007	(   catch(authorized(admin(edit_settings)), _, fail)
 1008	->  Edit = true
 1009	;   authorized(admin(read_settings)),
 1010	    Edit = false
 1011	),
 1012	reply_html_page(cliopatria(default),
 1013			title('Settings'),
 1014			[ h1('Application settings'),
 1015			  \http_show_settings([ edit(Edit),
 1016						hide_module(false),
 1017						action('save_settings')
 1018					      ]),
 1019			  \warn_no_edit(Edit)
 1020			]).
 1021
 1022warn_no_edit(true) --> !.
 1023warn_no_edit(_) -->
 1024	html(p(id(settings_no_edit),
 1025	       [ a(href(location_by_id(login_form)), 'Login'),
 1026		 ' as ', code(admin), ' to edit the settings.' ])).
 save_settings(+Request)
Save modified settings.
 1032save_settings(Request) :-
 1033	authorized(admin(edit_settings)),
 1034	reply_html_page(cliopatria(default),
 1035			title('Save settings'),
 1036			\http_apply_settings(Request, [save(true)])).
 1037
 1038
 1039		 /*******************************
 1040		 *		EMIT		*
 1041		 *******************************/
 hidden(+Name, +Value)
Create a hidden input field with given name and value
 1047hidden(Name, Value) -->
 1048	html(input([ type(hidden),
 1049		     name(Name),
 1050		     value(Value)
 1051		   ])).
 1052
 1053action(URL, Label) -->
 1054	html([a([href(URL)], Label), br([])])