head	1.121;
access;
symbols
	TIGRIS_1_1_0RC2:1.54.2.7.4.6
	TIGRIS_1_1_0RC1:1.54.2.7.4.6
	TIGRIS_1_1:1.54.2.7.4.6.0.2
	TIGRIS_1_0_8:1.54.2.7.4.6
	TIGRIS_1_0_8RC3:1.54.2.7.4.6
	TIGRIS_1_0_8RC2:1.54.2.7.4.6
	TIGRIS_1_0_8RC1:1.54.2.7.4.6
	TIGRIS_1_0_7:1.54.2.7.4.6
	TIGRIS_1_0_7RC3:1.54.2.7.4.6
	TIGRIS_1_0_7RC2:1.54.2.7.4.6
	TIGRIS_1_0_7RC1:1.54.2.7.4.6
	TIGRIS_1_0_6:1.54.2.7.4.6
	TIGRIS_1_0_6RC5:1.54.2.7.4.6
	TIGRIS_1_0_6RC4:1.54.2.7.4.6
	TIGRIS_1_0_6RC3:1.54.2.7.4.6
	TIGRIS_1_0_6RC2:1.54.2.7.4.6
	TIGRIS_1_0_6RC1:1.54.2.7.4.6
	TIGRIS_1_0_5:1.54.2.7.4.4
	TIGRIS_1_0_5RC6:1.54.2.7.4.4
	TIGRIS_1_0_5RC5:1.54.2.7.4.4
	TIGRIS_1_0_5RC4:1.54.2.7.4.3
	TIGRIS_1_0_5RC3:1.54.2.7.4.3
	TIGRIS_1_0_5RC2:1.54.2.7.4.3
	TIGRIS_1_0_5RC1:1.54.2.7.4.2
	TIGRIS_1_0_4:1.54.2.7.4.1
	TIGRIS_1_0_3:1.54.2.7
	TIGRIS_1_0_2:1.54.2.7
	TIGRIS_1_0_1:1.54.2.7
	TIGRIS_1_0:1.54.2.7.0.4
	TIGRIS_1_0_0:1.54.2.7
	TIGRIS_1_0_0_RC1:1.54.0.2
	dlr:1.1.1
	HELM_PEER_PORT_BRANCH:1.1.1.1;
locks; strict;
comment	@# @;


1.121
date	2001.08.30.17.24.36;	author dlr;	state Exp;
branches;
next	1.120;

1.120
date	2001.08.30.17.15.54;	author dlr;	state Exp;
branches;
next	1.119;

1.119
date	2001.08.30.17.05.19;	author dlr;	state Exp;
branches;
next	1.118;

1.118
date	2001.08.30.00.38.21;	author dlr;	state Exp;
branches;
next	1.117;

1.117
date	2001.08.29.22.15.23;	author dlr;	state Exp;
branches;
next	1.116;

1.116
date	2001.08.29.21.33.18;	author dlr;	state Exp;
branches;
next	1.115;

1.115
date	2001.08.29.19.07.50;	author dlr;	state Exp;
branches;
next	1.114;

1.114
date	2001.08.29.16.38.11;	author dlr;	state Exp;
branches;
next	1.113;

1.113
date	2001.08.29.00.48.39;	author dlr;	state Exp;
branches;
next	1.112;

1.112
date	2001.08.22.15.42.34;	author leonardr;	state Exp;
branches;
next	1.111;

1.111
date	2001.08.17.21.30.23;	author leonardr;	state Exp;
branches;
next	1.110;

1.110
date	2001.08.15.18.50.53;	author leonardr;	state Exp;
branches;
next	1.109;

1.109
date	2001.08.13.19.04.32;	author leonardr;	state Exp;
branches;
next	1.108;

1.108
date	2001.08.13.17.48.41;	author leonardr;	state Exp;
branches;
next	1.107;

1.107
date	2001.08.11.09.08.04;	author dlr;	state Exp;
branches;
next	1.106;

1.106
date	2001.08.10.16.37.20;	author leonardr;	state Exp;
branches;
next	1.105;

1.105
date	2001.08.06.22.12.23;	author dlr;	state Exp;
branches;
next	1.104;

1.104
date	2001.07.30.19.29.57;	author leonardr;	state Exp;
branches;
next	1.103;

1.103
date	2001.07.30.18.40.41;	author leonardr;	state Exp;
branches;
next	1.102;

1.102
date	2001.07.30.18.11.49;	author dlr;	state Exp;
branches;
next	1.101;

1.101
date	2001.07.27.23.02.35;	author stack;	state Exp;
branches;
next	1.100;

1.100
date	2001.07.27.19.18.00;	author leonardr;	state Exp;
branches;
next	1.99;

1.99
date	2001.07.26.18.58.54;	author leonardr;	state Exp;
branches;
next	1.98;

1.98
date	2001.07.25.19.39.26;	author leonardr;	state Exp;
branches;
next	1.97;

1.97
date	2001.07.19.19.08.42;	author dlr;	state Exp;
branches;
next	1.96;

1.96
date	2001.07.19.18.42.22;	author dlr;	state Exp;
branches;
next	1.95;

1.95
date	2001.07.18.09.45.59;	author dlr;	state Exp;
branches;
next	1.94;

1.94
date	2001.07.17.03.22.04;	author jrobbins;	state Exp;
branches;
next	1.93;

1.93
date	2001.07.06.21.51.53;	author leonardr;	state Exp;
branches;
next	1.92;

1.92
date	2001.07.06.19.59.04;	author leonardr;	state Exp;
branches;
next	1.91;

1.91
date	2001.07.06.16.15.46;	author leonardr;	state Exp;
branches;
next	1.90;

1.90
date	2001.07.02.21.41.46;	author leonardr;	state Exp;
branches;
next	1.89;

1.89
date	2001.07.02.18.56.42;	author leonardr;	state Exp;
branches;
next	1.88;

1.88
date	2001.06.26.01.00.01;	author edk;	state Exp;
branches;
next	1.87;

1.87
date	2001.06.26.00.57.14;	author edk;	state Exp;
branches;
next	1.86;

1.86
date	2001.06.18.22.12.20;	author leonardr;	state Exp;
branches;
next	1.85;

1.85
date	2001.06.13.17.30.16;	author leonardr;	state Exp;
branches;
next	1.84;

1.84
date	2001.06.13.16.41.11;	author leonardr;	state Exp;
branches;
next	1.83;

1.83
date	2001.06.09.01.13.20;	author leonardr;	state Exp;
branches;
next	1.82;

1.82
date	2001.06.09.01.02.15;	author leonardr;	state Exp;
branches;
next	1.81;

1.81
date	2001.06.07.03.13.00;	author dlr;	state Exp;
branches;
next	1.80;

1.80
date	2001.06.07.02.57.36;	author dlr;	state Exp;
branches;
next	1.79;

1.79
date	2001.06.06.16.42.44;	author edk;	state Exp;
branches;
next	1.78;

1.78
date	2001.06.06.16.13.37;	author edk;	state Exp;
branches;
next	1.77;

1.77
date	2001.06.05.18.53.08;	author leonardr;	state Exp;
branches;
next	1.76;

1.76
date	2001.05.25.19.29.35;	author leonardr;	state Exp;
branches;
next	1.75;

1.75
date	2001.05.25.16.43.13;	author leonardr;	state Exp;
branches;
next	1.74;

1.74
date	2001.05.23.01.50.13;	author dlr;	state Exp;
branches;
next	1.73;

1.73
date	2001.05.22.23.35.53;	author leonardr;	state Exp;
branches;
next	1.72;

1.72
date	2001.05.17.14.51.17;	author leonardr;	state Exp;
branches;
next	1.71;

1.71
date	2001.05.11.19.38.55;	author leonardr;	state Exp;
branches;
next	1.70;

1.70
date	2001.05.10.01.26.36;	author dlr;	state Exp;
branches;
next	1.69;

1.69
date	2001.05.02.16.24.52;	author leonardr;	state Exp;
branches;
next	1.68;

1.68
date	2001.05.02.08.11.04;	author dlr;	state Exp;
branches;
next	1.67;

1.67
date	2001.04.30.18.19.24;	author leonardr;	state Exp;
branches;
next	1.66;

1.66
date	2001.04.20.21.19.40;	author leonardr;	state Exp;
branches;
next	1.65;

1.65
date	2001.04.12.20.40.40;	author leonardr;	state Exp;
branches;
next	1.64;

1.64
date	2001.04.11.17.42.12;	author leonardr;	state Exp;
branches;
next	1.63;

1.63
date	2001.04.09.23.44.44;	author leonardr;	state Exp;
branches;
next	1.62;

1.62
date	2001.04.05.02.20.50;	author leonardr;	state Exp;
branches;
next	1.61;

1.61
date	2001.04.04.00.44.29;	author leonardr;	state Exp;
branches;
next	1.60;

1.60
date	2001.04.03.09.27.28;	author manoj;	state Exp;
branches;
next	1.59;

1.59
date	2001.03.30.00.25.57;	author leonardr;	state Exp;
branches;
next	1.58;

1.58
date	2001.03.29.22.13.34;	author leonardr;	state Exp;
branches;
next	1.57;

1.57
date	2001.03.29.05.22.29;	author edk;	state Exp;
branches;
next	1.56;

1.56
date	2001.03.29.04.50.37;	author edk;	state Exp;
branches;
next	1.55;

1.55
date	2001.03.28.23.08.00;	author leonardr;	state Exp;
branches;
next	1.54;

1.54
date	2001.03.22.01.27.54;	author dlr;	state Exp;
branches
	1.54.2.1;
next	1.53;

1.53
date	2001.03.22.01.24.43;	author leonardr;	state Exp;
branches;
next	1.52;

1.52
date	2001.03.22.01.09.26;	author dlr;	state Exp;
branches;
next	1.51;

1.51
date	2001.03.20.16.42.05;	author leonardr;	state Exp;
branches;
next	1.50;

1.50
date	2001.03.16.02.46.52;	author elicia;	state Exp;
branches;
next	1.49;

1.49
date	2001.03.13.19.08.00;	author leonardr;	state Exp;
branches;
next	1.48;

1.48
date	2001.03.13.03.53.01;	author dlr;	state Exp;
branches;
next	1.47;

1.47
date	2001.03.13.03.32.33;	author leonardr;	state Exp;
branches;
next	1.46;

1.46
date	2001.03.13.03.15.03;	author leonardr;	state Exp;
branches;
next	1.45;

1.45
date	2001.03.09.21.59.29;	author elicia;	state Exp;
branches;
next	1.44;

1.44
date	2001.03.08.03.30.42;	author dlr;	state Exp;
branches;
next	1.43;

1.43
date	2001.03.07.01.53.22;	author lucas;	state Exp;
branches;
next	1.42;

1.42
date	2001.03.06.07.52.33;	author dlr;	state Exp;
branches;
next	1.41;

1.41
date	2001.03.06.07.45.43;	author dlr;	state Exp;
branches;
next	1.40;

1.40
date	2001.03.06.04.04.53;	author elicia;	state Exp;
branches;
next	1.39;

1.39
date	2001.03.06.00.31.39;	author leonardr;	state Exp;
branches;
next	1.38;

1.38
date	2001.03.05.19.28.22;	author leonardr;	state Exp;
branches;
next	1.37;

1.37
date	2001.03.05.18.08.50;	author leonardr;	state Exp;
branches;
next	1.36;

1.36
date	2001.03.02.23.34.35;	author dlr;	state Exp;
branches;
next	1.35;

1.35
date	2001.03.02.23.26.25;	author dlr;	state Exp;
branches;
next	1.34;

1.34
date	2001.03.02.23.14.04;	author dlr;	state Exp;
branches;
next	1.33;

1.33
date	2001.03.02.22.58.10;	author dlr;	state Exp;
branches;
next	1.32;

1.32
date	2001.03.02.22.43.38;	author dlr;	state Exp;
branches;
next	1.31;

1.31
date	2001.03.02.22.28.37;	author elicia;	state Exp;
branches;
next	1.30;

1.30
date	2001.03.02.21.40.14;	author dlr;	state Exp;
branches;
next	1.29;

1.29
date	2001.03.01.03.29.33;	author elicia;	state Exp;
branches;
next	1.28;

1.28
date	2001.02.27.23.29.13;	author leonardr;	state Exp;
branches;
next	1.27;

1.27
date	2001.02.27.22.15.12;	author leonardr;	state Exp;
branches;
next	1.26;

1.26
date	2001.02.27.09.13.55;	author dlr;	state Exp;
branches;
next	1.25;

1.25
date	2001.02.27.03.28.03;	author dlr;	state Exp;
branches;
next	1.24;

1.24
date	2001.02.27.02.51.27;	author dlr;	state Exp;
branches;
next	1.23;

1.23
date	2001.02.26.23.35.02;	author leonardr;	state Exp;
branches;
next	1.22;

1.22
date	2001.02.26.22.03.25;	author leonardr;	state Exp;
branches;
next	1.21;

1.21
date	2001.02.24.11.29.40;	author dlr;	state Exp;
branches;
next	1.20;

1.20
date	2001.02.24.11.25.25;	author dlr;	state Exp;
branches;
next	1.19;

1.19
date	2001.02.24.11.18.09;	author dlr;	state Exp;
branches;
next	1.18;

1.18
date	2001.02.24.11.16.33;	author dlr;	state Exp;
branches;
next	1.17;

1.17
date	2001.02.24.04.08.58;	author dlr;	state Exp;
branches;
next	1.16;

1.16
date	2001.02.24.03.28.51;	author dlr;	state Exp;
branches;
next	1.15;

1.15
date	2001.02.24.03.22.07;	author dlr;	state Exp;
branches;
next	1.14;

1.14
date	2001.02.23.19.09.51;	author leonardr;	state Exp;
branches;
next	1.13;

1.13
date	2001.02.23.17.01.11;	author leonardr;	state Exp;
branches;
next	1.12;

1.12
date	2001.02.23.03.03.31;	author leonardr;	state Exp;
branches;
next	1.11;

1.11
date	2001.02.23.02.58.39;	author leonardr;	state Exp;
branches;
next	1.10;

1.10
date	2001.02.22.21.37.21;	author leonardr;	state Exp;
branches;
next	1.9;

1.9
date	2001.02.22.15.36.14;	author leonardr;	state Exp;
branches;
next	1.8;

1.8
date	2001.02.22.02.39.42;	author leonardr;	state Exp;
branches;
next	1.7;

1.7
date	2001.02.22.01.29.53;	author dlr;	state Exp;
branches;
next	1.6;

1.6
date	2001.02.22.00.38.46;	author dlr;	state Exp;
branches;
next	1.5;

1.5
date	2001.02.21.05.36.23;	author edk;	state Exp;
branches;
next	1.4;

1.4
date	2001.02.21.05.03.19;	author edk;	state Exp;
branches;
next	1.3;

1.3
date	2001.02.21.04.38.18;	author dlr;	state Exp;
branches;
next	1.2;

1.2
date	2001.02.21.03.02.22;	author edk;	state Exp;
branches;
next	1.1;

1.1
date	2001.01.28.01.18.22;	author dlr;	state dead;
branches
	1.1.1.1
	1.1.2.1;
next	;

1.1.1.1
date	2001.02.21.00.33.05;	author dlr;	state Exp;
branches;
next	;

1.1.2.1
date	2001.01.28.01.18.22;	author dlr;	state Exp;
branches;
next	1.1.2.2;

1.1.2.2
date	2001.01.29.20.10.45;	author dlr;	state Exp;
branches;
next	1.1.2.3;

1.1.2.3
date	2001.01.29.22.10.24;	author dlr;	state Exp;
branches;
next	1.1.2.4;

1.1.2.4
date	2001.01.29.23.12.47;	author dlr;	state Exp;
branches;
next	1.1.2.5;

1.1.2.5
date	2001.01.30.00.01.06;	author dlr;	state Exp;
branches;
next	1.1.2.6;

1.1.2.6
date	2001.01.30.06.27.01;	author dlr;	state Exp;
branches;
next	1.1.2.7;

1.1.2.7
date	2001.01.30.07.07.12;	author dlr;	state Exp;
branches;
next	1.1.2.8;

1.1.2.8
date	2001.01.30.19.48.03;	author leonardr;	state Exp;
branches;
next	1.1.2.9;

1.1.2.9
date	2001.01.30.21.38.43;	author leonardr;	state Exp;
branches;
next	1.1.2.10;

1.1.2.10
date	2001.01.30.23.56.37;	author leonardr;	state Exp;
branches;
next	1.1.2.11;

1.1.2.11
date	2001.01.31.00.06.46;	author dlr;	state Exp;
branches;
next	1.1.2.12;

1.1.2.12
date	2001.01.31.00.15.06;	author dlr;	state Exp;
branches;
next	1.1.2.13;

1.1.2.13
date	2001.01.31.00.16.29;	author dlr;	state Exp;
branches;
next	1.1.2.14;

1.1.2.14
date	2001.01.31.01.03.41;	author dlr;	state Exp;
branches;
next	1.1.2.15;

1.1.2.15
date	2001.01.31.01.08.09;	author dlr;	state Exp;
branches;
next	1.1.2.16;

1.1.2.16
date	2001.01.31.02.17.04;	author dlr;	state Exp;
branches;
next	1.1.2.17;

1.1.2.17
date	2001.01.31.02.59.57;	author leonardr;	state Exp;
branches;
next	1.1.2.18;

1.1.2.18
date	2001.01.31.21.51.37;	author dlr;	state Exp;
branches;
next	1.1.2.19;

1.1.2.19
date	2001.02.01.02.57.46;	author leonardr;	state Exp;
branches;
next	1.1.2.20;

1.1.2.20
date	2001.02.01.17.54.05;	author dlr;	state Exp;
branches;
next	1.1.2.21;

1.1.2.21
date	2001.02.01.18.26.10;	author dlr;	state Exp;
branches;
next	1.1.2.22;

1.1.2.22
date	2001.02.01.20.40.23;	author leonardr;	state Exp;
branches;
next	1.1.2.23;

1.1.2.23
date	2001.02.02.17.38.13;	author dlr;	state Exp;
branches;
next	1.1.2.24;

1.1.2.24
date	2001.02.02.18.13.30;	author dlr;	state Exp;
branches;
next	1.1.2.25;

1.1.2.25
date	2001.02.02.18.18.00;	author dlr;	state Exp;
branches;
next	1.1.2.26;

1.1.2.26
date	2001.02.05.15.40.56;	author leonardr;	state Exp;
branches;
next	1.1.2.27;

1.1.2.27
date	2001.02.05.20.24.02;	author leonardr;	state Exp;
branches;
next	1.1.2.28;

1.1.2.28
date	2001.02.06.17.53.58;	author leonardr;	state Exp;
branches;
next	1.1.2.29;

1.1.2.29
date	2001.02.06.18.14.11;	author dlr;	state Exp;
branches;
next	1.1.2.30;

1.1.2.30
date	2001.02.06.18.55.44;	author leonardr;	state Exp;
branches;
next	1.1.2.31;

1.1.2.31
date	2001.02.06.19.07.58;	author leonardr;	state Exp;
branches;
next	1.1.2.32;

1.1.2.32
date	2001.02.06.19.09.04;	author dlr;	state Exp;
branches;
next	1.1.2.33;

1.1.2.33
date	2001.02.08.01.15.46;	author elicia;	state Exp;
branches;
next	1.1.2.34;

1.1.2.34
date	2001.02.08.01.54.32;	author elicia;	state Exp;
branches;
next	1.1.2.35;

1.1.2.35
date	2001.02.08.16.09.01;	author leonardr;	state Exp;
branches;
next	1.1.2.36;

1.1.2.36
date	2001.02.09.03.07.33;	author dlr;	state Exp;
branches;
next	1.1.2.37;

1.1.2.37
date	2001.02.10.00.35.52;	author leonardr;	state Exp;
branches;
next	1.1.2.38;

1.1.2.38
date	2001.02.10.01.14.02;	author leonardr;	state Exp;
branches;
next	1.1.2.39;

1.1.2.39
date	2001.02.10.02.20.48;	author leonardr;	state Exp;
branches;
next	1.1.2.40;

1.1.2.40
date	2001.02.12.16.24.32;	author leonardr;	state Exp;
branches;
next	1.1.2.41;

1.1.2.41
date	2001.02.12.18.50.37;	author leonardr;	state Exp;
branches;
next	1.1.2.42;

1.1.2.42
date	2001.02.12.22.47.15;	author leonardr;	state Exp;
branches;
next	1.1.2.43;

1.1.2.43
date	2001.02.12.23.35.01;	author dlr;	state Exp;
branches;
next	1.1.2.44;

1.1.2.44
date	2001.02.13.03.35.34;	author leonardr;	state Exp;
branches;
next	1.1.2.45;

1.1.2.45
date	2001.02.13.19.52.29;	author leonardr;	state Exp;
branches;
next	1.1.2.46;

1.1.2.46
date	2001.02.13.21.27.47;	author leonardr;	state Exp;
branches;
next	1.1.2.47;

1.1.2.47
date	2001.02.14.23.20.29;	author leonardr;	state Exp;
branches;
next	1.1.2.48;

1.1.2.48
date	2001.02.15.20.50.38;	author leonardr;	state Exp;
branches;
next	1.1.2.49;

1.1.2.49
date	2001.02.16.02.02.16;	author leonardr;	state Exp;
branches;
next	1.1.2.50;

1.1.2.50
date	2001.02.16.02.08.15;	author leonardr;	state Exp;
branches;
next	1.1.2.51;

1.1.2.51
date	2001.02.16.03.01.27;	author dlr;	state Exp;
branches;
next	1.1.2.52;

1.1.2.52
date	2001.02.16.16.09.07;	author leonardr;	state Exp;
branches;
next	1.1.2.53;

1.1.2.53
date	2001.02.16.16.26.36;	author leonardr;	state Exp;
branches;
next	1.1.2.54;

1.1.2.54
date	2001.02.16.21.19.39;	author leonardr;	state Exp;
branches;
next	1.1.2.55;

1.1.2.55
date	2001.02.16.22.21.40;	author leonardr;	state Exp;
branches;
next	1.1.2.56;

1.1.2.56
date	2001.02.17.00.19.31;	author leonardr;	state Exp;
branches;
next	;

1.54.2.1
date	2001.03.28.19.22.27;	author leonardr;	state Exp;
branches;
next	1.54.2.2;

1.54.2.2
date	2001.03.29.04.52.00;	author edk;	state Exp;
branches;
next	1.54.2.3;

1.54.2.3
date	2001.03.29.05.21.59;	author edk;	state Exp;
branches;
next	1.54.2.4;

1.54.2.4
date	2001.03.29.22.18.35;	author dlr;	state Exp;
branches;
next	1.54.2.5;

1.54.2.5
date	2001.03.30.09.54.50;	author dlr;	state Exp;
branches;
next	1.54.2.6;

1.54.2.6
date	2001.04.04.01.04.52;	author dlr;	state Exp;
branches;
next	1.54.2.7;

1.54.2.7
date	2001.04.05.21.59.58;	author dlr;	state Exp;
branches
	1.54.2.7.4.1;
next	;

1.54.2.7.4.1
date	2001.05.02.16.25.00;	author leonardr;	state Exp;
branches;
next	1.54.2.7.4.2;

1.54.2.7.4.2
date	2001.05.10.02.10.26;	author dlr;	state Exp;
branches;
next	1.54.2.7.4.3;

1.54.2.7.4.3
date	2001.05.16.00.29.28;	author leonardr;	state Exp;
branches;
next	1.54.2.7.4.4;

1.54.2.7.4.4
date	2001.05.19.01.20.32;	author leonardr;	state Exp;
branches;
next	1.54.2.7.4.5;

1.54.2.7.4.5
date	2001.05.24.23.31.09;	author leonardr;	state Exp;
branches;
next	1.54.2.7.4.6;

1.54.2.7.4.6
date	2001.06.01.19.26.36;	author leonardr;	state Exp;
branches;
next	;


desc
@@


1.121
log
@Added overload for hasApprovedRoleInProject which passes in a null
Role reference.  Used in template.
@
text
@/* ================================================================
 * Copyright (c) 2000-2001 CollabNet.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if
 * any, must include the following acknowlegement: "This product includes
 * software developed by CollabNet (http://www.collab.net/)."
 * Alternately, this acknowlegement may appear in the software itself, if
 * and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@@collab.net.
 * 
 * 5. Products derived from this software may not use the "Tigris" name
 * nor may "Tigris" appear in their names without prior written
 * permission of CollabNet.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL COLLABNET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals on behalf of CollabNet.
 */

package org.tigris.helm.om;

import java.util.*;

//import org.apache.torque.util.BasePeer;
import org.apache.torque.util.Criteria;
import org.apache.commons.util.ObjectUtils;
import org.apache.commons.util.StringUtils;
import org.apache.turbine.util.Log;
import org.apache.commons.util.exception.NestableException;
import org.apache.fulcrum.TurbineServices;
import org.apache.fulcrum.InstantiationException;
import org.apache.fulcrum.velocity.TurbineVelocity;

import gnu.regexp.*;

import org.apache.velocity.VelocityContext;
import org.apache.velocity.context.Context;

import org.tigris.anzu.client.MailingAliasSpec;

import org.tigris.helm.*;
import org.tigris.helm.util.URL;
import org.tigris.helm.security.*;
import org.tigris.helm.tool.*;
import org.tigris.helm.tool.task.TaskException;
import org.tigris.helm.tool.audit.AuditLog;
import org.tigris.helm.event.ToolEvent;

/** 
 * User business object.
 *
 * @@author <a href="mailto:leonardr@@collab.net">Leonard Richardson</a>
 * @@author <a href="mailto:dlr@@collab.net">Daniel Rall</a>
 * @@version $Id: User.java,v 1.120 2001/08/30 17:15:54 dlr Exp $
 */
public class User extends BaseUser implements UserType, Comparable
{

    /**
     * Message to use when the user tries to do something to a deleted
     * account.
     */
    private static final String DELETED_ACCOUNT_MESSAGE = 
        "This user account has been deleted. You may not modify it";

    /**
     * Description of the audit log entry created when a user of this
     * type is added.  
     */
    private static final String AUDIT_LOG_ON_ADD = "User added: ";

    /**
     * Description of the audit log entry created when a user of this
     * type is deleted.
     */
    private static final String AUDIT_LOG_ON_DELETE = "User deleted: ";

    /**
     * Description of the audit log entry created when a user of this
     * type is edited.
     */
    private static final String AUDIT_LOG_ON_EDIT = "User edited: ";

    /**
     * Description of the audit log entry created when a user of this
     * type is granted a role.
     */
    private static final String AUDIT_LOG_ON_ROLE_GRANT =
        "Role granted to user: ";

    /**
     * Description of the audit log entry created when a role is
     * revoked from a user of this type.  
     */
    private static final String AUDIT_LOG_ON_ROLE_REVOKE =
        "Role revoked from user: ";

    /**
     * The name of the template used to create the body of the user role 
     * request email.
     */
    private static final String ROLE_REQUESTED_TEMPLATE = 
        TemplateTool.getPathToMessageTemplate("UserRoleRequest.vm");

    /**
     * The name of the template used to create the body of the requested
     * role approval email.
     */
    private static final String ROLE_REQUEST_APPROVED_TEMPLATE = 
        TemplateTool.getPathToMessageTemplate("RequestedRoleApproved.vm");

    /**
     * The name of the template used to create the body of the requested
     * role denial email.
     */
    private static final String ROLE_REQUEST_DENIED_TEMPLATE = 
        TemplateTool.getPathToMessageTemplate("RequestedRoleDenied.vm");

    /**
     * The name of the template used to create the body of the welcome
     * message the new user receives.
     */
    private static final String WELCOME_TMPL = 
        TemplateTool.getPathToRemoteBrandingTemplate("welcome.vm");

    /**
     * The regular expression used to validate login names.
     */
    private static RE loginNameRE;

    /**
     * The regular expression used to validate real names.
     */
    private static RE realNameRE;

    /**
     * Static initializer; initialize regular expressions.
     */
    static
    {
        try
        {
            // HELP: Are these things thread safe?
            loginNameRE = new RE("^[\\w][\\w_]{0,15}$");
            realNameRE = new RE("^[\\w' \\-\\.\\,\\(\\)]+$");
        }
        catch (REException e)
        {
            throw new Error
                ("Could not initialize regular expressions for user.");
        }
    }

    /**
     * Description of the user.
     */
    public final String toString()
    {
        String name = null;
        try 
        {
            name = getDomain().getName() + "/" + getLoginName();
        }
        catch (Exception ignore)
        {
            name = "[unknown domain]/" + getLoginName();
        }
        return name;
    }

    /**
     * Hashtable containing a description of the user account.
     *
     * Used by the xmlrpc handlers.  If value is null, we 
     * return the empty string.  xmlrpc does not support nulls
     * (nor exceptions).
     */
    public final Hashtable asHashtable()
    {
        Hashtable t = new Hashtable();
        hashPutCheckForNull(t,"id", getID());
        hashPutCheckForNull(t,"loginName", getLoginName());
        hashPutCheckForNull(t,"realName", getRealName());
        hashPutCheckForNull(t,"email", getEmail());
        return t;
    }

    /**
     * Throws an exception if the user has been deleted.
     */
    public void assertNondeletion()
        throws Exception
    {
        if (isDeleted())
        {
            throw new NestableException(DELETED_ACCOUNT_MESSAGE);
        }
    }

    /**
     * Throws an exception if the specified information corresponds to an
     * existing user.
     *  
     * @@param domain    The domain to check.
     * @@param loginName The login name of the user to search for.
     */
    public static void assertNonexistance(Domain domain, String loginName)
        throws AlreadyExists, Exception
    {
        Criteria c = new Criteria()
            .add(UserPeer.LOGIN_NAME, loginName);
        UserPeer.checkThisAndHostDomain(c, domain);
        List u = UserPeer.doSelect(c);
        if (!u.isEmpty()) 
        {
            User user = (User)u.get(0);
            String type = "User";
            if (user.isDeleted())
            {
                type += " (deleted)";
            }
            throw new AlreadyExists(type + " with loginName of " + loginName,
                                    "domain " + domain.getName());
        }
    }

    /**
     * Checks whether a login name is valid.
     *
     * @@param loginName The login name to check.
     * @@return          Whether the name is valid.
     */
    public static boolean isValidLoginName (String loginName)
    {
        return (loginName != null && loginNameRE.isMatch(loginName));
    }

    /**
     * Checks whether a real name is valid.
     *
     * @@param realName The real name to check.
     * @@return         Whether the name is valid.
     */
    public static boolean isValidRealName (String realName)
    {
        return (realName != null && realNameRE.isMatch(realName));
    }

    /**
     * Checks whether the user matches the provided identity.  If no
     * {@@link org.tigris.helm.tool.IdentityVerificationService} is
     * defined in <code>TurbineResources.properties</code>, we assume
     * that all relevant verification has already been done.  Note that
     * Helm does not come with a default
     * {@@link org.tigris.helm.tool.IdentityVerificationService}.
     */
    public boolean matchesIdentity(Context ctx)
    {
        boolean match = false;
        try
        {
            IdentityVerificationService idVerifier =
                (IdentityVerificationService) TurbineServices.getInstance()
                .getService(IdentityVerificationService.SERVICE_NAME);
            match = idVerifier.verify(this, ctx);
        }
        catch (InstantiationException noIDVerfier)
        {
            match = true;
        }
        return match;
    }

    /**
     * Returns the ID of this user's domain as a string.
     */
    public final Domain getDomain()
        throws Exception
    {
        return (Domain)ProjectPeer.getInstance(getDomainID());
    }

    /**
     * Returns the ID of this user's domain as a string.
     */
    public final String getDomainID()
    {
        return String.valueOf(getDomainId());
    }

    /**
     * Returns the site email address for this user.
     */
    public String getDomainEmail()
        throws Exception
    {
        String domName = getDomain().getName();
        return getLoginName() + "@@" + domName;
    } 

    /**
     * Returns the human-readable, capitalized type of this user.
     */
    public String getHumanReadableType()
    {
        String type = getType();
        if (type.equals(UserType.REGULAR_TYPE))
        {
            type = "User";
        }
        else
        {
            type = StringUtils.firstLetterCaps(type);
        }
        return type;
    }

    /**
     * Returns true iff this user represents the users in a domain.
     */
    public boolean isDomain()
    {
        return (this instanceof DomainUserGroup);
    }

    /**
     * Returns true iff this user represents the users in the host domain.
     */    
    public boolean isHost()
    {
        return (this instanceof HostUserGroup);
    }

    /**
     * Returns true iff this user represents an admin-defined usergroup.
     */
    public boolean isGroup()
    {
        return (this instanceof UserGroup);
    }

    /**
     * Returns true iff this User object represents an actual user of
     * the site who can log in.  
     */
    public boolean isBase()
        throws Exception
    {
        //TODO: Check for other special accounts like postmaster, etc.
        return (!isGroup() && !isNobody());
    }

    /**
     * Determines whether the user is the application's guest user.  Useful in
     * WebMacro template code.
     *
     * @@return Whether the guest user.
     */
    public final boolean isAnonymous()
        throws Exception
    {
        return equals(UserPeer.getAnonymousUser());
    }
 
   /**
     * Determines whether the user is the special "nobody" user.
     *
     * @@return Whether the special "nobody".
     */
    public final boolean isNobody()
        throws Exception
    {
        return equals(UserPeer.getNobodyUser());
    }

    /**
     * Determines whether the user is the superuser.
     *
     * @@return Whether the superuser.
     */
    public final boolean isSuperUser()
        throws Exception
    {
        return equals(UserPeer.getSuperUser());
    }

    /**
     * Returns true iff this user has been deleted.
     */
    public boolean isDeleted()
    {
        return getType().equals(DELETED_TYPE);
    }

    /**
     * Compare this user to another object for sorting purposes.
     */
    public int compareTo(Object o)
        throws ClassCastException
    {
        User u = (User)o;
        return getRealName().compareTo(u.getRealName());
    }

    /**
     * Forces a rebuild of the ACL for this user. Calling it on a
     * UserGroup will rebuild the ACLs of everyone in the UserGroup.
     */
    public void rebuildACL()
        throws Exception
    {
        for (Iterator i = expand().iterator(); i.hasNext(); ) {
            AccessControlList.rebuildACL((User)i.next());
        }
    }

    /**
     * Obtains the ACL for this user.
     */
    public AccessControlList getACL()
        throws Exception, NestableException
    {
        return AccessControlList.getACL(this);
    }

    /**
     * Returns a list of the effective user IDs for this user. This
     * consists of the user's ID itself and ther user IDs of all groups
     * to which this user belongs.
     */
    public List effectiveUserIDs()
        throws Exception
    {
        Criteria c = new Criteria().add(UserUsergroupPeer.USER_ID,getID());
        List mappings = UserUsergroupPeer.doSelect(c);
        List myIDs = new ArrayList(mappings.size()+1);
        myIDs.add(getID());
        for (Iterator i = mappings.iterator(); i.hasNext();)
        {
            UserUsergroup g = (UserUsergroup)i.next();
            myIDs.add(g.getUserGroupID());
        }
        return myIDs;
    }
    
    /**
     * Returns true if this user is an owner of this project.
     */
    public boolean isProjectOwner(Project project)
        throws Exception
    {
        boolean isProjectOwner = false;
        List roles = getRolesInProject(project);
        for (Iterator i = roles.iterator(); i.hasNext();)
        {
            Role r = (Role)i.next();
            if (r.denotesOwner())
            {
                isProjectOwner = true;
                break;
            }
        }
        return isProjectOwner;
     }

    /**
     * Return a list of all groups to which this user belongs, not including
     * the special domain group.
     */
    public List getRegularGroups()
        throws Exception
    {
        List groups = getGroups();
        //There will probably be one fewer entry in the new list than
        //in the old, since every user belongs to one special group.
        List newGroups = new ArrayList(groups.size()-1);
        for (Iterator i = groups.iterator(); i.hasNext();)
        {
            User u = (User)i.next();
            if (!(u.isDomain() || u.isHost()))
            {
                newGroups.add(u);
            }
        }
        return newGroups;
    }

    /**
     * Return a list of all groups to which this user belongs, including
     * the special domain group.
     */
    public List getGroups()
        throws Exception
    {
        Criteria c = new Criteria()
            .addJoin(UserUsergroupPeer.USER_GROUP_ID, UserPeer.USER_ID)
            .add(UserUsergroupPeer.USER_ID,getID());
        return UserPeer.doSelect(c);        
    }


    /**
     * Return a list of the most recent 10 news items for the projects
     * The user is a member of.
     */
    public List getNewsItemsForUser()
        throws Exception
    {
        int limit = 10;
        Criteria c = new Criteria()
            .addJoin(ProjectPeer.PROJECT_ID, UserRoleProjectPeer.PROJECT_ID)
            .addJoin(ProjectPeer.PROJECT_ID, NewsItemPeer.PROJECT_ID)
            .add(UserRoleProjectPeer.USER_ID, getID())
            .add(NewsItemPeer.APPROVED_BY, 
                 UserPeer.getNobodyUser().getUserId(), Criteria.NOT_EQUAL)
            .addDescendingOrderByColumn(NewsItemPeer.EVENT_DATE);

        c.setDistinct();

        //NOTE: This may not be exactly what we want, since news items
        //we've suggested that haven't yet been approved will show up
        //in isViewableBy, and we might not want that. But it's much closer
        //to what we want than what was here before.
        List potentials = NewsItemPeer.doSelect(c);        
        List actuals = new ArrayList(limit);
        for (Iterator i = potentials.iterator(); i.hasNext();)
        {
            NewsItem n = (NewsItem)i.next();
            if (n.isViewableBy(getACL()))
            {
                actuals.add(n);
                if (actuals.size() >= limit)
                {
                    break;
                }
            }
        }
        return actuals;
    }

    /**
     * Returns a list of Users represending all the users this user represents.
     * If called on a base user, returns a list containing only itself.
     */    
    public List expand()
        throws Exception
    {
        List users = new ArrayList(1);
        users.add(this);
        return users;
    }

    /**
     * Creates and saves a new password ticket.
     */
    public String newPasswordTicket()
        throws Exception
    {
        String ticket = Nonce.buildNonce();
        setPasswordTicket(ticket);
        save();
        return ticket;
    }

    /**
     * Removes a used password ticket.
     */
    public final void clearPasswordTicket()
        throws Exception
    {
        setPasswordTicket(null);
        save();
    }

    /**
     * Determines whether the password ticket is valid.
     *
     * @@param ticket The ticket to compare.
     */
    public boolean isValidPasswordTicket (String ticket)
        throws Exception
    {
        return (ticket != null && 
                ticket.equals(getPasswordTicket()));
    }

    /**
     * Sends a email with a URL containing a ticket used to validate a change
     * of password for the user.  Using this ticket and having the user come to
     * the site to change their password prevents a DOS attack against the user
     * that would be possible if we just changed the password and emailed it
     * directly instead.
     */
    public void sendNewPasswordTicket (Context context, String subject, 
                                       String template)
        throws DoesNotExist, Exception
    {
        String ticket = newPasswordTicket();

        String url = URL.makeHostURL(ContextAPI.getRequest(context), null) +
            "/servlets/PasswordEdit";
        url = URL.appendCGIParam(url, "userID", getID());
        url = URL.appendCGIParam(url, "ticket", ticket);
        
        Context ctx = new VelocityContext();
        ctx.put("user", this);
        ctx.put("url", url);
        String body = TurbineVelocity.handleRequest(ctx, template);
        new HelmEmailer().mailUserFromSystem(this, subject, body);
    }

    //
    // Mutator methods
    //

    /**
     * Adds a new base user.
     */
    public static User add
        (AccessControlList acl, Domain domain, String realName, 
         String loginName, String type)
        throws ACLException, AlreadyExists, Exception
    {
        return add(acl, domain, realName, loginName, null, null, null, type);
    }

    /**
     * Adds a new base user.
     */
    public static User add
        (AccessControlList acl, Domain domain, String realName,
         String loginName, String password, String email)
        throws ACLException, AlreadyExists, Exception
    {
        User u = add(acl, domain, realName, loginName, password, email, null, 
                     REGULAR_TYPE);
        return u;
    }

    /**
     * Adds a new base user.
     */
    public static User add 
        (AccessControlList acl, Domain domain, String realName,
         String loginName, String password, String email, String organization,
         boolean sendWelcomeEmail)
        throws ACLException, AlreadyExists, Exception
    {
        return add(acl, domain, false, realName, loginName, password, email,
                   organization, sendWelcomeEmail, REGULAR_TYPE);
    }

    /**
     * Adds a new user of the specified type. 
     */
    public static User add 
        (AccessControlList acl, Domain domain, String realName,
         String loginName, String password, String email, String organization,
         String type)
        throws ACLException, AlreadyExists, Exception
    {
        return add(acl, domain, false, realName, loginName,
                   password, email, organization, true, type);
    }


    /**
     * Registers a new user with the site.
     */
    public static User register
        (AccessControlList acl, Domain domain, String realName,
         String loginName, String password, String email, String organization)
        throws ACLException, AlreadyExists, Exception
    {
        String type = REGULAR_TYPE;
        return add(acl, domain, true, realName,
                   loginName, password, email, organization, true, type);
    }

    /**
     * Adds a new user of the specified type. 
     */
    private static User add
        (AccessControlList acl, Domain domain, boolean joining, 
         String realName, String loginName, String password, 
         String email, String organization, boolean sendWelcomeEmail, 
         String type)
        throws ACLException, AlreadyExists, Exception
    {
        //Make sure the user doesn't already exist.
        assertNonexistance(domain, loginName);

        if (type.equals(REGULAR_TYPE)) 
        {
            setEmailAnzu(domain, loginName, email, true);
        }

        User user = new User();
        try 
        {
            user.setDomainId(domain.getID());
            user.setRealName(realName);
            user.setLoginName(loginName);
            user.setPassword(UserPeer.encryptPassword(password));
            user.setEmail(email);
            user.setOrganization(organization);
            user.setType(type);
            user.assertAddPermission(acl, joining);
            user.save();

            //Add the user to the appropriate user group.
            user.addToDomainGroup();
        }
        catch (Exception e) 
        {
            if (type.equals(REGULAR_TYPE)) 
            {
                deleteEmailAnzu(domain, loginName);
            }
            throw new NestableException("Unable to finish creating User", e);
        }

        AuditLog.logEvent(acl.getUser(), domain, user.AUDIT_LOG_ON_ADD 
                          + user.getLoginName());

        if (sendWelcomeEmail)
        {
            // Send welcome email message to new user.
            String shortSiteName = 
                HelmProperties.getProperty(Domain.SHORT_SITE_NAME_KEY);
            if (!StringUtils.isValid(shortSiteName))
            {
                shortSiteName = HelmProperties.getProperty("DOMAIN");
                if (!StringUtils.isValid(shortSiteName))
                {
                    shortSiteName = "SourceCast";
                }
            }
            String subject = "Welcome to " + shortSiteName;
            Context ctx = new VelocityContext();
            ctx.put("user", user);
            ctx.put("domainName", domain.getName());
            String canStartProject = "false";
            if (user.getACL().hasPermission("Project - Suggest", domain))
            { 
                canStartProject = "true";
            }
            ctx.put("canStartProject", canStartProject);
            String body = TurbineVelocity.handleRequest(ctx, WELCOME_TMPL);
            HelmEmailer emailer = new HelmEmailer();
            emailer.sendEmail(user.getEmail(), subject, body);
        }

        ToolEvent.userAdded(user);

        return user;
    }

    /**
     * TODO: Clean up password update scheme.
     *
     * @@exception Exception Passwords did not match or internal error.
     */
    public void update(AccessControlList acl, String email, 
                       String realName, String organization, 
                       String oldPassword, String password, 
                       String passwordConfirm)
        throws ACLException, Exception
    {
        if (!password.equals(passwordConfirm))
        {
            throw new Exception("Passwords do not match.");
        }
        assertEditPermission(acl);
        
        // TODO : this should really go in the setEmail method ... but
        // Torque's generated factory methods -- in UserPeer.row2object --
        // would call it, which would be bad. -edk
        if (!email.equals(getEmail()) && getType().equals(REGULAR_TYPE))
        {
            setEmailAnzu(getDomain(), getLoginName(), email, false);
        }
        if (!userEditSelfAllowsEditOrganization() &&
                !acl.hasPermission("User - Edit", getDomain())) {
            organization = getOrganization();
        }

        if (!"".equals(password))
        {
            changePassword(acl, oldPassword, password, passwordConfirm);
        }
         
        if (realName != null) setRealName(realName);
        if (email != null) setEmail(email);
        if (organization != null) setOrganization(organization);
        AuditLog.logEvent(acl.getUser(), getDomain(), AUDIT_LOG_ON_EDIT
                          + getLoginName());
        save();         
    }
    
    /**
     * Updates the user's password.
     *
     * @@param passwd        The new password to use.
     * @@param passwdConfirm Confirmation of the new password.
     *
     * @@exception ACLException Insufficient permission.
     * @@exception Exception    The passwords do not match, or an unexpected
     *                         error occurred.
     */
    public void changePassword(AccessControlList acl, String oldPassword,
                               String password, String passwordConfirm)
        throws ACLException, Exception
    {
        assertEditPermission(acl);
        if (!acl.hasPermission("User - Edit", getDomain()))
        {
            //They don't have general edit permission; they need to
            //verify their old password.
            if (!validPassword(oldPassword))
            {
                throw new Exception("Incorrect password.");
            }
        }
        changePassword(password, passwordConfirm);
    }

    /**
     * Updates the user's password.
     *
     * @@param passwd        The new password to use.
     * @@param passwdConfirm Confirmation of the new password.
     *
     * @@exception ACLException Insufficient permission.
     * @@exception Exception    The passwords do not match, or an unexpected
     *                         error occurred.
     */
    public void changePassword(String ticket, String password,
                               String passwordConfirm)
        throws ACLException, Exception
    {
        if (ticket == null)
        {
            throw new Exception("No password ticket specified.");
        }

        if (!isValidPasswordTicket(ticket))
        {
            throw new Exception("Password ticket " + ticket 
                                + " is not valid. It may have been used already.");
        }
        changePassword(password, passwordConfirm);
        clearPasswordTicket();
    }

    /**
     * Updates the user's password without doing any permission
     * checking.
     */
    public void changePassword(String password, String passwordConfirm)
        throws Exception
    {
        if (password != null && passwordConfirm != null)
        {
            if (password.equals(passwordConfirm)) 
            {
                setPassword(UserPeer.encryptPassword(password));
                save();                
            }
            else 
            {
                throw new Exception("Passwords did not match");
            }
        }
    }

    /**
     * This method sets the email address on the anzu server.  It handles
     * host level users specially ...
     */
    private static void setEmailAnzu(Domain domain, String loginName,
            String email, boolean create) throws Exception
    {
        try
        {
            if (!domain.isHost())
            {
                MailingAliasSpec alias = new MailingAliasSpec(domain.getName(), 
                        ProjectPeer.DEFAULT_PROJECT_NAME, loginName);
                alias.setDestination(email);
                if (create)
                    alias.create();
                else
                    alias.update();
            }
            else
            {
                // do the above for each domain.  we could combine the two
                // if we constructed a container ... but that's unnecessary
                // object instanciation in the most common case.  probably
                // anzu should have a concept of host level items like this...
                //
                // TODO put a method in Domain to allow client code to
                // get the list of all domains.  that won't be necessary if
                // anzu is changed as above.
                List domains = ProjectPeer.getHost().getDomains();
                Iterator i = domains.iterator();
                while(i.hasNext())
                {
                    Domain nextDomain = (Domain)i.next();
                    if (nextDomain.isHost())
                        continue;
                    MailingAliasSpec alias =
                        new MailingAliasSpec(nextDomain.getName(), 
                                ProjectPeer.DEFAULT_PROJECT_NAME, loginName);
                    alias.setDestination(email);
                    if (create)
                        alias.create();
                    else
                        alias.update();
                }
            }
        }
        catch (Exception e)
        {
            throw new TaskException(e);
        }
    }

    /**
     * This method deletes the email address on the anzu server.  It
     * handles host level users specially...
     */
    private static void deleteEmailAnzu(Domain domain, String loginName)
        throws TaskException
    {
        try 
        {
            MailingAliasSpec alias =
                new MailingAliasSpec(domain.getName(), "www", loginName);
            alias.delete();
        } 
        catch (Exception e) 
        {
            throw new TaskException(e);
        }              
    }
    
    /**
     * Deletes the corresponding user record from the database.
     *
     * @@param acl The ACL of the user performing the delete.
     *
     * @@exception Exception Likely a database error.
     */
    public void delete(AccessControlList acl)
        throws ACLException, Exception
    {
        Domain domain = getDomain();
        assertDeletePermission(acl);

        User deletingUser = acl.getUser();
        //Remove the user from all composite users.
        for (Iterator i = getGroups().iterator(); i.hasNext();)
        {
            UserGroup u = (UserGroup)i.next();
            removeFromGroup(acl, u);
        }               

        //Revoke all the user's roles, requested or granted.
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId());
        UserRoleProjectPeer.doDelete(c);

        // remove the Anzu alias
        deleteEmailAnzu(domain, getLoginName());

        ToolEvent.userDeleted(this);

        //Remove the user proper.
        setPassword(null);
        setType(DELETED_TYPE);
        save(true);

        AuditLog.logEvent(acl.getUser(), getDomain(), AUDIT_LOG_ON_DELETE
                          + getLoginName());
     }

    //
    // Group management
    //

    public void addToDomainGroup()
        throws Exception
    {
        AccessControlList acl = AccessControlList.getSuperUserACL();
        try 
        {
            UserPeer.getDomainUser(getDomain()).addUser(acl, this);        
        }
        catch (ACLException e) 
        {
            throw new Error
                ("Super user lacks permission to add user to group.");
        }
    }

    public void addToGroup(AccessControlList acl, UserGroup g)
        throws ACLException, Exception
    {
        g.addUser(acl, this);
    }

    public void removeFromGroup(AccessControlList acl, UserGroup g)
        throws ACLException, Exception
    {
        g.removeUser(acl, this);
    }

    //
    // Role and permission management - accessor methods
    //

    /**
     * Returns true iff this user is visible by the given ACL.
     */
    public final boolean isViewableBy (AccessControlList acl)
        throws Exception
    {
        boolean viewable = false;
        if (acl.hasPermission("User - View", getDomain())
            || (acl.getUser().getID().equals(getID()) &&
                acl.hasPermission("User - View - Self", getDomain())))
        {
            viewable = true;
        }
        return viewable;
    }

    /**
     * Throws an exception unless the user has permission sufficient to
     * add this user to the database.
     */
    public void assertAddPermission(AccessControlList acl, boolean register)
        throws ACLException, Exception
    {
        if (isBase()) 
        {
            if (register)
            {
                acl.assertPermission("Domain - Join", getDomain());
            }
            else
            {
                acl.assertPermission("User - Add", getDomain());
            }
        }
        else 
        {
            acl.assertPermission("UserGroup - Add", getDomain());
        }
    }

    /**
     * Throws an exception unless the user has permission sufficient to
     * delete this user.
     */
    public void assertDeletePermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (isBase()) 
        {
            acl.assertPermission("User - Delete", getDomain());
        }
        else 
        {
            acl.assertPermission("UserGroup - Delete", getDomain());
        }
    }

    /**
     * Returns true iff the user has permission sufficient to delete
     * this user.  
     */
    public boolean hasDeletePermission(AccessControlList acl)
        throws Exception
    {
        boolean ok = false;
        if (isBase()) {
            ok = acl.hasPermission("User - Delete", getDomain());
        }
        else {
            ok = acl.hasPermission("UserGroup - Delete", getDomain());
        }
        return ok;
    }

    /**
     * Throw an exception unless the provided ACL has permission sufficient
     * to edit this user's information.
     */
    public void assertEditPermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (!isEditableBy(acl))
        {
            throw new ACLException(acl, "User edit permission", 
                                   "Domain " + getDomain().getName(), null);
        }
    }

    /**
     * Returns true iff the provided ACL has permission sufficient to
     * edit this user's information.  When a user edits themself, the
     * permission check happens against a lesser permission.
     */
    public boolean isEditableBy(AccessControlList acl)
        throws Exception
    {
        return ( (acl.getUserID().equals(getID()) &&
                  acl.hasPermission("User - Edit - Self", getDomain())) ||
                 acl.hasPermission("User - Edit", getDomain()) );
    }

    /**
     * Returns true iff the given password matches the password in the
     * database.
     */
    public boolean validPassword (String password)
    {
        return (password != null &&
                UserPeer.encryptPassword(password).equals(getPassword()));
    }

    /**
     * Returns true iff the user (as distinct from any groups to which
     * they belong) has requested the given role in the given project.
     *
     * @@param role The role to check for approval, or
     * <code>null</code> if any role will do.
     * @@param project The project to to check for roles in.
     * @@return Whether approved role exists.
     */
    public boolean hasApprovedRoleInProject(Role role, Project project)
        throws Exception
    {
        Criteria c = UserRoleProjectPeer.approvedRoleCriteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId());
        if (role != null)
        {
            c.add(UserRoleProjectPeer.ROLE_ID, role.getID());
        }
        c.add(UserRoleProjectPeer.PROJECT_ID, project.getID());
        List roles = UserRoleProjectPeer.doSelect(c);
        return (!roles.isEmpty());
    }

    /**
     * @@see #hasApprovedRoleInProject(Role, Project)
     */
    public final boolean hasApprovedRoleInProject(Project project)
        throws Exception
    {
        return hasApprovedRoleInProject(null, project);
    }

    /**
     * Returns true iff the user has requested the given role in the
     * given project.  
     */
    public boolean hasRequestedRoleInProject(Role role, Project project)
        throws Exception
    {
        Criteria c = new Criteria(4)
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.ROLE_ID, role.getID())
            .add(UserRoleProjectPeer.PROJECT_ID, project.getID())
            .add(UserRoleProjectPeer.APPROVED_BY,
                 UserPeer.getNobodyUser().getUserId());
        List roles = UserRoleProjectPeer.doSelect(c);
        return (!roles.isEmpty());
    }

    /**
     * Returns true iff the provided ACL has permission sufficient to
     * look at this user's information.  
     */
    public void assertViewPermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (acl.getUserID().equals(getID())) {
            acl.assertPermission("User - View - Self", getDomain());
        }
        else {
            acl.assertPermission("User - View", getDomain());
        }
    }

    /**
     * Throws an ACLException if this user cannot grant roles in the
     * given project.  Note that the grant permission implies revoke
     * as well.  
     */
    public void assertRoleGrantPermission (Project project)
        throws ACLException, Exception
    {
        getACL().assertPermission
            (project.requiredRoleGrantAction(), project);
    }

    /**
     * Returns true if this user can grant roles in the given
     * project.  Note that the grant permission implies revoke as
     * well.  
     */
    public boolean hasRoleGrantPermission (Project project)
        throws Exception
    {
        return getACL().hasPermission
            (project.requiredRoleGrantAction(), project);
    }

    /**
     * Returns true if this user can grant roles in the given
     * project.  Note that the grant permission implies revoke as
     * well.  
     */
    public boolean canRevokeRole(User user, Project project)
        throws Exception
    {
        boolean ok = false;
        if (user.getID().equals(getID()))
        {
            //Users may always revoke their own roles.
            ok = true;
        } 
        else 
        {
            ok = hasRoleGrantPermission(project);
        }
        return ok;
    }

    /**
     * User - Edit - Self is may not be sufficient to change organization,
     * depending on site policy.  We default to disallowing this.
     */
    public static boolean userEditSelfAllowsEditOrganization()
    {
        String userEditSelfAllowsEditOrgProperty = HelmProperties.getProperty(
                Domain.USER_EDIT_SELF_ALLOWS_EDIT_ORGANIZATION_KEY);
        boolean canEdit = false;
        if (userEditSelfAllowsEditOrgProperty != null &&
            new Boolean(userEditSelfAllowsEditOrgProperty).booleanValue())
        {
            canEdit = true;
        }
        return canEdit;
    }

    /**
     * Returns all non-special projects in which this user has an
     * approved role.
     */
    public List getProjectsForUser()
        throws Exception
    {        
        Object[] types = {Project.HOST_TYPE, Project.DOMAIN_TYPE};
        Criteria c = UserRoleProjectPeer.approvedRoleCriteria()
            .addJoin(UserRoleProjectPeer.PROJECT_ID, ProjectPeer.PROJECT_ID)
            .add(UserRoleProjectPeer.USER_ID, getID())
            .addNotIn(ProjectPeer.TYPE, types);
        c.setDistinct();
        Log.debug("Projects for user: " + c);            
        return ProjectPeer.doSelect(c);
    }

    /**
     * Returns the list of all projects in which this user has taken
     * an explicit interest, <i>plus</i> any projects from
     * <code>ofInterest</code>.
     *
     * @@param ofInterest Additional projects of interest, or
     * <code>null</code> to initialize to a correctly pre-allocated
     * <code>List</code>.
     * @@return The projects of interest.
     */
    private Collection collectProjectsOfInterestTo(Collection ofInterest)
        throws Exception
    {
        Criteria c = new Criteria()
            .add(UserProjectInterestPeer.USER_ID, getID());
        List projInterests = UserProjectInterestPeer.doSelectJoinProject(c);
        if (ofInterest == null)
        {
            ofInterest = new ArrayList(projInterests.size());
        }

        Iterator i = projInterests.iterator();
        while (i.hasNext())
        {
            ofInterest.add( ((UserProjectInterest) i.next()).getProject() );
        }
        return ofInterest;
    }

    /**
     * Checks whether user is already interested in a project against
     * all projects this user is interested in (including those of
     * which the user has a role in).
     *
     * @@return Whether the project is already of interest.
     */
    public boolean isAlreadyInterestedBy(Project project)
        throws Exception
    {
        Set projects = getAllProjectsOfInterestTo();
        for (Iterator i = projects.iterator(); i.hasNext(); )
        {
            if ( ((Project) i.next()).equals(project) )
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns the list of all projects in which this user has taken
     * an explicit interest.
     */
    public List getProjectsOfInterestTo()
        throws Exception
    {
        return (List) collectProjectsOfInterestTo(null);
    }

    /**
     * Returns the set of all non-special projects in which this user
     * has an approved role, <i>plus</i> those in which they've taken
     * an interest.
     */
    public Set getAllProjectsOfInterestTo()
        throws Exception
    {
        Set projects = new HashSet(getProjectsForUser());
        return (Set) collectProjectsOfInterestTo(projects);
    }

    /**
     * Returns all projects in which this user has an approved role.
     */
    public List getAllProjectsWithApprovedRole()
        throws Exception
    {
        Criteria c = UserRoleProjectPeer.approvedRoleCriteria()
            .addJoin(UserRoleProjectPeer.PROJECT_ID,
                     ProjectPeer.PROJECT_ID)
            .add(UserRoleProjectPeer.USER_ID, getID());
        c.setDistinct();
        return ProjectPeer.doSelect(c);
    }
    
    /**
     * Returns all the requestable project roles which the user does
     * not currently posess (in granted or requested form) in the given
     * project
     */
    public List getAvailableRolesInProject (Project project)
        throws Exception
    {
        List roles = project.getRequestableRoles();
        List requested = getRequestedRolesInProject(project); 
        requested.addAll(getRolesInProject(project));
        roles.removeAll(requested);
        return roles;
    }

    /**
     * Returns all the roles which a user has been granted in a project.
     */
    public List getRolesInProject (Project project)
        throws Exception
    {
        return getRolesInProject(project, true);
    }

    /**
     * Returns all the roles which a user has requested in a project.
     */
    public List getRequestedRolesInProject (Project project)
        throws Exception
    {
        return getRolesInProject(project, false);
    }

    /**
     * Does the heavy lifting for the public getRolesInProject and
     * getRequestedRolesInProject.  
     */
    private List getRolesInProject (Project project, boolean approved)
        throws Exception
    {
        String matchType = approved?Criteria.NOT_EQUAL:Criteria.EQUAL;
        List roles = new ArrayList ();
        Criteria c = new Criteria()
            .addJoin(RolePeer.ROLE_ID, UserRoleProjectPeer.ROLE_ID)
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.PROJECT_ID, project.getProjectId())
            .add(UserRoleProjectPeer.APPROVED_BY, 
                 UserPeer.getNobodyUser().getUserId(), matchType);
        return RolePeer.doSelect(c);
    }

    /**
     * Returns all the projects in which the user has the given role
     * (approved).
     */
    public List getProjectsWithRole(Role role)
        throws Exception
    {
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getID())
            .add(UserRoleProjectPeer.ROLE_ID, role.getID())
            .addJoin(ProjectPeer.PROJECT_ID, UserRoleProjectPeer.PROJECT_ID)
            .add(UserRoleProjectPeer.APPROVED_BY, 
                 UserPeer.getNobodyUser().getUserId(), Criteria.NOT_EQUAL);
        return ProjectPeer.doSelect(c);
    }

    /**
     * Convenience method to send email to a user regarding a role.
     */
    private void mailUserAboutRole(String templateName, String subject,
                                   Role role, Project project, String reason)
        throws Exception
    {
        Context ctx = new VelocityContext();
        ctx.put("user", this);
        ctx.put("role", role);
        ctx.put("project", project);
        if (reason != null && !"".equals(reason))
        {
            ctx.put("reason", reason);
        }
        String body = TurbineVelocity.handleRequest(ctx, templateName);
        new HelmEmailer().mailUserFromSystem(this, subject, body.toString());
    }

    //
    // Role and permission management - mutator methods
    //

    /**
     * Requests for this user the specified role in the specified project.
     */
    public void requestRole(Role role, Project project)
        throws ACLException, Exception
    {
        AccessControlList acl = getACL();
        acl.assertPermission("Role - Request", project);
        requestRoleWithoutCheck(role, project);
    }

    /**
     * Requests for this user the specified role in the specified project,
     * burning the specified ticket in leiu of an ACL check.
     */
    public void requestRole(String ticket, Role role, Project project)
        throws Exception
    {
        Invitation invitation = InvitationPeer.getInstance(ticket);
        if (invitation == null)
        {
            throw new Exception(Invitation.BAD_TICKET_MESSAGE);
        }

        if (!invitation.isMatch(project))
        {            
            throw new Exception (Invitation.WRONG_PROJECT_FOR_TICKET_MESSAGE);
        }
        
        requestRoleWithoutCheck(role, project);
        invitation.delete();
    }

    /**
     * Requests for this user the specified role in the specified project.
     */
    private void requestRoleWithoutCheck(Role role, Project project)
        throws ACLException, Exception
    {
        UserRoleProject mapping = new UserRoleProject();
        mapping.setUserId(getUserId());
        mapping.setRoleId(role.getRoleId());
        mapping.setProjectId(project.getProjectId());
        mapping.setApprovedBy(UserPeer.getNobodyUser().getUserId());
        mapping.save();

        String subject = "New role requested";
        Context ctx = new VelocityContext();
        ctx.put("user", this);
        ctx.put("role", role);
        ctx.put("project", project);
        String body = TurbineVelocity.handleRequest(ctx,
                                                    ROLE_REQUESTED_TEMPLATE);
        HelmEmailer emailer = new HelmEmailer();
        emailer.messageUsersWithProjectOwnership
            (project, subject, body.toString());
    }

    /**
     * Approves an already requested role.
     */
    public void approveRole(AccessControlList acl, Role role, Project project)
        throws ACLException, Exception
    {        
        boolean alreadyHadRole = grantRole(acl, role, project);
        if (!alreadyHadRole)
        {
            mailUserAboutRole(ROLE_REQUEST_APPROVED_TEMPLATE,
                              "Requested role has been granted", 
                              role, project, null);
        }
    }

    /**
     * Disapproves a requested role.
     */
    public void disapproveRole(AccessControlList acl, Role role, 
                               Project project)
        throws ACLException, Exception
    {        
        disapproveRole(acl, role, project, null);
    }

    /**
     * Disapproves a requested role.
     */
    public void disapproveRole(AccessControlList acl, Role role, 
                               Project project, String disapprovalReason)
        throws ACLException, Exception
    {        
        //TODO: don't mail user if user hadn't requested this role.
        revokeRole(acl, role, project);

        mailUserAboutRole(ROLE_REQUEST_DENIED_TEMPLATE,
                          "Requested role has not been granted", 
                          role, project, disapprovalReason);
    }

    /**
     * Grants to this user the specified role in the host.
     */
    public void grantHostRole(AccessControlList acl, Role role)
        throws ACLException, Exception
    {
        grantRole(acl, role, ProjectPeer.getHost());
    }

    /**
     * Grants to this user the specified role in the specified project.
     * @@return Whether or not the user already had the role.
     */
    public boolean grantRole(AccessControlList acl, Role role, Project project)
        throws ACLException, Exception
    {        
        User approving = acl.getUser();
        approving.assertRoleGrantPermission(project);
        return grantRole(approving, role, project);
    }

    /**
     * Grants to this user the specified role in the specified project.
     * @@return Whether or not the user already had the role.
     */
    protected boolean grantRole(User approving, Role role, Project project)
        throws Exception
    {
        boolean alreadyHadRole = true;
        UserRoleProject mapping = null;

        assertNondeletion();

        //We get an error if we try to grant a role someone already
        //has, so check for one first. 
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.ROLE_ID, role.getRoleId())
            .add(UserRoleProjectPeer.PROJECT_ID, project.getProjectId());
        try 
        {
            mapping = (UserRoleProject)
                PeerTool.getFirstBO(UserRoleProjectPeer.doSelect(c), "");
            if (mapping.getUserRelatedByApprovedBy().equals(UserPeer.getNobodyUser()))
            {
                alreadyHadRole = false;
            }
        } 
        catch (DoesNotExist e) 
        {
            mapping = new UserRoleProject();
            alreadyHadRole=false;
        }

        if (!alreadyHadRole)
        {
            
            mapping.setUserId(getUserId());
            mapping.setRoleId(role.getRoleId());
            mapping.setProjectId(project.getProjectId());
            mapping.setApprovedBy(approving.getUserId());
            mapping.save();
            
            // Invalidate the user's ACL.
            AccessControlList.rebuildACL(this);
            
            // People in charge of a project should have their names
            // names in a special alias -- owner@@{project}.{domain}
            if (role.denotesOwner() && role.getType().equals(Role.PROJECT_TYPE)) 
            {
                AnzuTask.setOwnerAlias(this, project, true);
            }
            
            AuditLog.logEvent(approving, project, AUDIT_LOG_ON_ROLE_GRANT 
                              + getLoginName() + " <- " + role.getName());
        }
        return alreadyHadRole;
    }

    /**
     * Revokes from this user a role in the host.
     */
    public void revokeHostRole(AccessControlList acl, Role role)
        throws ACLException, Exception
    {
        revokeRole(acl, role, ProjectPeer.getHost());
    }

    /**
     * Revokes from this user a role in the specified project.
     */
    public void revokeRole(AccessControlList acl, Role role, Project project)
        throws ACLException, Exception
    {        
        //If they can't revoke their role, throw an ACLException
        if (!acl.getUser().canRevokeRole(this, project))
        {
            acl.getUser().assertRoleGrantPermission(project);
        }

        assertNondeletion();

        //The superuser cannot lose a role which gives them ownership over the
        //host, or that is their only source of one of the system unlosable
        //permissions.
        if (isSuperUser())
        {
            if (role.denotesOwner() && role.getType().equals(Role.HOST_TYPE))
            {
                throw new Exception
                    ("Superuser cannot lose host ownership role.");
            }

            List permissions = role.getPermissions();
            for (Iterator i = permissions.iterator(); i.hasNext();)
            {
                Action action = ((Permission)i.next()).getAction();
                String type = action.getType();
                if (Action.HOST_TYPE.equals(type) 
                    || Action.DOMAIN_TYPE.equals(type))
                {
                    if (getACL().wouldLosePermissionWithout(action, role))
                    {
                        throw new Exception 
                            ("Superuser would lose the " + action.getName()
                             + " action if the " + role.getName() 
                             + " role were revoked.");
                    }
                }
            }
        }

        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.ROLE_ID, role.getRoleId())
            .add(UserRoleProjectPeer.PROJECT_ID, project.getProjectId());
        UserRoleProjectPeer.doDelete(c);

        // Invalidate the user's ACL.
        AccessControlList.rebuildACL(this);

        // TODO: If they no longer have any ownership roles,
        // remove them from the member list.
        AuditLog.logEvent(acl.getUser(), project, AUDIT_LOG_ON_ROLE_REVOKE
                          + getLoginName() + " -> " + role.getName());
    }

    /**
     * Grants the <code>Click Through Viewer</code> role to a user.
     *
     * @@param domain The domain to grant the role in.
     *
     * @@exception DoesNotExist User, role, or project not found.
     */
    public void setClickThroughAsViewed(Domain domain)
        throws DoesNotExist, Exception
    {
        Role role = RolePeer.getInstanceByName("Click-through Viewer");
        User root = UserPeer.getSuperUser();
        grantRole(root.getACL(), role, domain);
    }


    /**
     * Overrides BaseUser save to remove this user from the cache.  There might
     * be a cached representation of the user associated with this key floating
     * around.
     */ 
    public void save()
        throws Exception
    {
        save(false);
    }

    /**
     * Overrides BaseUser save to remove this user from the cache.  There might
     * be a cached representation of the user associated with this key floating
     * around.
     *
     * @@param Whether this save is to mark a user as deleted.
     */ 
    private void save(boolean deleting)
        throws Exception
    {
        if (deleting)
        {
            if (isHost() || isDomain() || isNobody())
            {
                throw new NestableException("This user cannot be deleted.");
            }
        }
        else
        {
            if (isDeleted())
            {
                throw new NestableException(DELETED_ACCOUNT_MESSAGE);
            }
        }
        super.save();
        uncache();
    }

    // Deprecated methods.

    /**
     * @@deprecated Use isAnonymous() instead.
     */
    public final boolean isGuest()
        throws Exception
    {
        return isAnonymous();
    }

    /**
     * Returns a UserGroup version of this object.
     *
     * @@deprecated Cast instead; if you used doSelect you'll have no
     *             problems.
     */
    public UserGroup asGroup()
    {
        return (UserGroup)this;
    }
}
@


1.120
log
@Added JavaDoc to hasApprovedRoleInProject, and allowed for null to be
passed in for the Role parameter.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.119 2001/08/30 17:05:19 dlr Exp $
d1183 9
@


1.119
log
@Broke long line.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.118 2001/08/30 00:38:21 dlr Exp $
d1164 6
a1169 1
     * they belong) has requested the given role in the given project.  
d1175 6
a1180 3
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.ROLE_ID, role.getID())
            .add(UserRoleProjectPeer.PROJECT_ID, project.getID());
@


1.118
log
@Added isAlreadyInterestedBy(Project) instance method.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.117 2001/08/29 22:15:23 dlr Exp $
d115 2
a116 1
    private static final String AUDIT_LOG_ON_ROLE_GRANT = "Role granted to user: ";
@


1.117
log
@Reworked getAllProjectsOfInterestTo and getProjectsOfInterestTo to use
new third method.  getProjectsOfInterestTo had been returning UPI
objects instead of Project objects.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.116 2001/08/29 21:33:18 dlr Exp $
d1314 21
@


1.116
log
@Added new interest list retrieval method and renamed old.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.115 2001/08/29 19:07:50 dlr Exp $
d1289 29
d1323 1
a1323 3
        Criteria c = new Criteria()
            .add(UserProjectInterestPeer.USER_ID, getID());
        return UserProjectInterestPeer.doSelectJoinProject(c);
d1334 2
a1335 11
        Set ofInterest = new HashSet(getProjectsForUser());

        // Add projects user has an interest in.
        List projInterests = getProjectsOfInterestTo();
        Iterator i = projInterests.iterator();
        while (i.hasNext())
        {
            ofInterest.add( ((UserProjectInterest) i.next()).getProject() );
        }

        return ofInterest;
@


1.115
log
@Shrank isEditableBy(AccessControlList) and enhanced its JavaDoc.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.114 2001/08/29 16:38:11 dlr Exp $
d1288 12
d1304 1
a1304 1
    public Set getProjectsOfInterestTo()
d1310 1
a1310 3
        Criteria c = new Criteria()
            .add(UserProjectInterestPeer.USER_ID, getID());
        List projInterests = UserProjectInterestPeer.doSelectJoinProject(c);
@


1.114
log
@JavaDoc tweak.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.113 2001/08/29 00:48:39 dlr Exp $
d1140 2
a1141 1
     * edit this user's information.
d1146 3
a1148 12
        boolean ok = false;
        if (acl.getUserID().equals(getID()) &&
            acl.hasPermission("User - Edit - Self", getDomain()))
        {
            ok = true;
        }

        if (!ok && acl.hasPermission("User - Edit", getDomain()))
        {
            ok = true;
        }
        return ok;
@


1.113
log
@Added getProjectsOfInterestTo() method.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.112 2001/08/22 15:42:34 leonardr Exp $
d1297 2
a1298 2
     * has an approved role, plus those in which they've taken an
     * interest.
@


1.112
log
@Made project deletions soft.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.111 2001/08/17 21:30:23 leonardr Exp $
d1293 23
@


1.111
log
@Removed security-hazardous debug message.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.110 2001/08/15 18:50:53 leonardr Exp $
d246 1
a246 1
                type += " (previously deleted)";
d1692 1
a1692 2
                throw new NestableException
                    ("This user has been deleted and its record may no longer be changed.");
@


1.110
log
@Fixed emberassing criteria bug, and added new method for determining whether you have an approved role in a project.
@
text
@d74 1
a74 1
import org.tigris.helm.tool.plugin.Plugins;
d81 1
a81 1
 * @@version $Id: User.java,v 1.109 2001/08/13 19:04:32 leonardr Exp $
d780 1
a780 1
        Plugins.fireUserAdded(user);
d1004 1
a1004 1
        Plugins.fireUserDeleted(this);
a1164 2
        Log.debug("Validating password " + UserPeer.encryptPassword(password) +
                  " against supplied password " + getPassword());
@


1.109
log
@PeerBackedList now knows about objects that come in grouped flavors, and can explain behavior in which a list consists of separate alphabetical lists of groups and of users.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.108 2001/08/13 17:48:41 leonardr Exp $
d1172 15
d1193 1
a1193 1
        Criteria c = new Criteria()
d1195 3
a1197 3
            .add(UserRoleProjectPeer.ROLE_ID, getUserId())
            .add(UserRoleProjectPeer.PROJECT_ID, getUserId())
            .add(UserRoleProjectPeer.APPROVED_BY, 
@


1.108
log
@Got rid of unused and obsolete import.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.107 2001/08/11 09:08:04 dlr Exp $
d326 17
@


1.107
log
@Upgrading to Turbine 3.0-dev, Fulcrum 1.0, and Torque 1.0.
@
text
@a55 1
import org.apache.turbine.util.ServletUtils;
d81 1
a81 1
 * @@version $Id: User.java,v 1.106 2001/08/10 16:37:20 leonardr Exp $
@


1.106
log
@Added Hashtable representation of Project for use in future XML-RPC handlers.
@
text
@d51 4
a54 5
//import org.apache.turbine.om.*;
import org.apache.turbine.om.peer.BasePeer;
import org.apache.turbine.util.db.Criteria;
import org.apache.turbine.util.ObjectUtils;
import org.apache.turbine.util.StringUtils;
d57 4
a60 4
import org.apache.turbine.util.TurbineException;
import org.apache.turbine.services.TurbineServices;
import org.apache.turbine.services.InstantiationException;
import org.apache.turbine.services.velocity.TurbineVelocity;
d64 1
d67 3
a69 1
import org.tigris.helm.tool.HelmProperties;
a70 1
import org.tigris.helm.*;
a71 3

import org.tigris.anzu.client.MailingAliasSpec;

d82 1
a82 1
 * @@version $Id: User.java,v 1.105 2001/08/06 22:12:23 dlr Exp $
d223 1
a223 1
            throw new TurbineException(DELETED_ACCOUNT_MESSAGE);
d431 1
a431 1
        throws Exception
d610 1
a610 1
        String url = ServletUtils.hostURL(ContextAPI.getRequest(context)) +
d615 1
a615 1
        Context ctx = TurbineVelocity.getContext();
d730 1
a730 1
            throw new TurbineException("Unable to finish creating User", e);
d750 1
a750 1
            Context ctx = TurbineVelocity.getContext();
d1354 1
a1354 1
        Context ctx = TurbineVelocity.getContext();
d1417 1
a1417 1
        Context ctx = TurbineVelocity.getContext();
d1656 1
a1656 1
                throw new TurbineException("This user cannot be deleted.");
d1663 1
a1663 1
                throw new TurbineException
@


1.105
log
@Cleaned up debug trace on validPassword() and removed exception no
longer thrown by encryptPassword().
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.104 2001/07/30 19:29:57 leonardr Exp $
a214 18
    }

    /**
     * Check for null string before 'putting' into hash.
     *
     * Insert empty string if we find a null.
     *
     * @@param inHash Hash to insert into.
     * @@param inKey
     * @@param inValue May be null.
     */
    private void hashPutCheckForNull( Hashtable inHash, String inKey, 
            String inValue )
    {
        if( inKey != null )
        {
            inHash.put( inKey, (inValue != null ? inValue: "") );
        }
@


1.104
log
@Stop coddling IZ in terms of user accounts; assume that IZ can get its permissions from Helm through the XML-RPC interface.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.103 2001/07/30 18:40:41 leonardr Exp $
a1167 1
        throws Exception
d1169 2
a1170 1
        Log.debug(getPassword() + " vs. " + UserPeer.encryptPassword(password));
@


1.103
log
@Action cleanup. Some role actions, and Audit Log - View, had three actions apiece when one would do. We're now down to 76 actions.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.102 2001/07/30 18:11:49 dlr Exp $
a1003 3
        // Having deleted the user from individual projects, delete
        // the user from the domain.  Mostly affects Issuezilla.
        HelmTask.deleteUser(deletingUser, domain, this);
a1543 1
            boolean rebuildIssueTracking = role.affectsIssueTracking();
a1560 4
            if (rebuildIssueTracking)
            {
                project.rebuildIssueTracking();
            }
a1619 2
        boolean rebuildIssueTracking = role.affectsIssueTracking();

a1627 5

        if (rebuildIssueTracking)
        {
            project.rebuildIssueTracking();
        }
@


1.102
log
@Removed extra set of parens to improve clarity.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.101 2001/07/27 23:02:35 stack Exp $
d1400 1
a1400 1
        acl.assertPermission("Project Role - Request", project);
@


1.101
log
@Check for null values when doing a put into a hash being returned by the
xmlrpc server. Set null values to the empty string as per a suggestion from
the xmlrpc.helma.org mailing list (xmlrpc spec. has no provision for
handling null values).
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.100 2001/07/27 19:18:00 leonardr Exp $
d231 1
a231 1
            inHash.put( inKey, ( ( inValue != null )? inValue: "" ) );
@


1.100
log
@Factored out user code into a separate XML-RPC handler.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.99 2001/07/26 18:58:54 leonardr Exp $
d202 4
d210 4
a213 4
        t.put("id", getID());
        t.put("loginName", getLoginName());
        t.put("realName", getRealName());
        t.put("email", getEmail());
d215 18
@


1.99
log
@Ed doesn't want underscore to be allowed as the first character of a
login name.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.98 2001/07/25 19:39:26 leonardr Exp $
d198 13
@


1.98
log
@User deletes are now soft deletes which change the user type to 'deleted' (a minimal type of user which has user information but is not allowed associations with roles or user groups). Includes some other miscellaneous bug fixes.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.97 2001/07/19 19:08:42 dlr Exp $
d173 1
a173 1
            loginNameRE = new RE("^[\\w_]{1,16}$");
@


1.97
log
@Updated to use Helm URL class (just ported from Joist).
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.96 2001/07/19 18:42:22 dlr Exp $
d88 8
d201 12
d226 9
a234 2
        if (!u.isEmpty()) {
            throw new AlreadyExists("User with loginName of " + loginName,
d383 1
a383 1
     * @@deprecated Use isAnonymous() instead.
d385 1
a385 2
    public final boolean isGuest()
        throws Exception
d387 1
a387 1
        return isAnonymous();
d932 2
a933 1
        try {            
d937 3
a939 1
        } catch (Exception e) {
a954 1
        String loginName = getLoginName();
d974 1
a974 1
        deleteEmailAnzu(domain, loginName);
d979 3
a981 2
        String message = AUDIT_LOG_ON_DELETE;
        UserPeer.doDelete(new Criteria().add(UserPeer.USER_ID, getID()));
d983 2
a984 1
        AuditLog.logEvent(acl.getUser(), getDomain(), message + loginName);
a1403 3
        //TODO: Add name to alias as per grantRole? (Such happens
        //in HEAD, but why?)

a1472 1
        Log.debug("Approving user: " + approving.getLoginName());
a1483 1
        Log.debug("Granting role: " + role.getName() + " " + project.getName());
d1487 2
d1503 3
a1505 1
        } catch (DoesNotExist e) {
d1561 2
d1630 1
d1639 28
d1672 9
@


1.96
log
@Updated in light of the port of Joist JoistProperties class to Helm (as class HelmProperties).
@
text
@d68 1
a68 1
import org.joist.util.URL;
d84 1
a84 1
 * @@version $Id: User.java,v 1.95 2001/07/18 09:45:59 dlr Exp $
@


1.95
log
@Separated PluginService into non-static description and separate static wrapper class (Plugins), which makes use of a PluginService singleton.
@
text
@d67 1
a67 1
import org.joist.util.JoistProperties;
d84 1
a84 1
 * @@version $Id: User.java,v 1.94 2001/07/17 03:22:04 jrobbins Exp $
d699 1
a699 1
                JoistProperties.getProperty(Domain.SHORT_SITE_NAME_KEY);
d702 1
a702 1
                shortSiteName = JoistProperties.getProperty("DOMAIN");
d1196 1
a1196 1
        String userEditSelfAllowsEditOrgProperty = JoistProperties.getProperty(
@


1.94
log
@added super simple plugin notification service
@
text
@d77 1
a77 1
import org.tigris.helm.tool.plugin.PluginService;
d84 1
a84 1
 * @@version $Id: User.java,v 1.93 2001/07/06 21:51:53 leonardr Exp $
d723 1
a723 1
        PluginService.fireUserAdded(user);
d948 1
a948 1
        PluginService.fireUserDeleted(this);
@


1.93
log
@Allow underscores in login names.
@
text
@d77 1
d84 1
a84 1
 * @@version $Id: User.java,v 1.92 2001/07/06 19:59:04 leonardr Exp $
d723 2
d947 2
@


1.92
log
@Welcome message and password ticket message are both consistently controlled by checkboxes.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.91 2001/07/06 16:15:46 leonardr Exp $
d164 1
a164 1
            loginNameRE = new RE("^[\\w]{1,16}$");
@


1.91
log
@Users without User - Edit must provide old password in order to change password.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.90 2001/07/02 21:41:46 leonardr Exp $
d613 2
a614 1
         String loginName, String password, String email, String organization)
d617 2
a618 2
        return add(acl, domain, realName, loginName, password, email,
                   organization, REGULAR_TYPE);
d631 1
a631 1
                   password, email, organization, type);
d645 1
a645 1
                   loginName, password, email, organization, type);
d652 3
a654 2
        (AccessControlList acl, Domain domain, boolean joining, String realName,
         String loginName, String password, String email, String organization,
d694 1
a694 3
        // Send welcome email message to new user.
        String shortSiteName = JoistProperties.getProperty(Domain.SHORT_SITE_NAME_KEY);
        if (!StringUtils.isValid(shortSiteName))
d696 3
a698 1
            shortSiteName = JoistProperties.getProperty("DOMAIN");
d701 14
a714 1
                shortSiteName = "SourceCast";
d716 4
a720 12
        Context ctx = TurbineVelocity.getContext();
        ctx.put("user", user);
        ctx.put("domainName", domain.getName());
        String canStartProject = "false";
        if (user.getACL().hasPermission("Project - Suggest", domain))
        { 
            canStartProject = "true";
        }
        ctx.put("canStartProject", canStartProject);
        String body = TurbineVelocity.handleRequest(ctx, WELCOME_TMPL);
        HelmEmailer emailer = new HelmEmailer();
        emailer.sendEmail(user.getEmail(), "Welcome to " + shortSiteName, body);
d826 1
a826 1
    private void changePassword(String password, String passwordConfirm)
@


1.90
log
@Prohibit actions which would cause root to lose a host or domain permission.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.89 2001/07/02 18:56:42 leonardr Exp $
d725 2
a726 1
                       String password, String passwordConfirm)
d749 1
a749 1
            changePassword(acl, password, passwordConfirm);
d770 2
a771 2
    public void changePassword(AccessControlList acl, String password,
                               String passwordConfirm)
d775 9
d1027 2
a1028 1
        if (isBase()) {
d1031 2
a1032 1
        else {
d1096 1
@


1.89
log
@Implemented project-scoped roles.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.88 2001/06/26 01:00:01 edk Exp $
d1506 5
a1510 5
        
        //Special case: The superuser cannot lose a role which gives
        //them ownership over the host.
        if (isSuperUser() && role.denotesOwner() 
            && role.getType().equals(Role.HOST_TYPE))
d1512 23
a1534 1
            throw new Exception("Superuser cannot lose host ownership role.");
@


1.88
log
@handle null check using the idiom which seems standard in this file
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.87 2001/06/26 00:57:14 edk Exp $
d1221 1
a1221 1
        List roles = ProjectPeer.getHost().getRequestableProjectRoles();
@


1.87
log
@our schema allows for a null password.  don't return NPE if you find one.
(this could be used for accts where logins shouldn't be allowed --
eg. postmaster, mailer-daemon, etc.)
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.86 2001/06/18 22:12:20 leonardr Exp $
d1084 2
a1085 3
        String encryptedPassword = getPassword();
        return (encryptedPassword != null &&
                encryptedPassword.equals(UserPeer.encryptPassword(password)));
@


1.86
log
@Huge patch of the day: Got rid of redundant HELM_DOMAIN table. The project representation of the domain and the host is now the canonical one. Host and Domain now subclass ProjectGroup. The canonical representation of a project's membership in a domain group is now the corresponding mapping in HELM_PROJECT_PROJECTGROUP. Schema changes: No more HELM_DOMAIN table (obviously); no more DOMAIN_ID in HELM_PROJECT; HELM_USER and HELM_VC_VIEW now have foreign keys in HELM_PROJECT instead of HELM_DOMAIN.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.85 2001/06/13 17:30:16 leonardr Exp $
d1084 3
a1086 1
        return (getPassword().equals(UserPeer.encryptPassword(password)));
@


1.85
log
@Added more places where unapproved roles are filtered out.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.84 2001/06/13 16:41:11 leonardr Exp $
d261 9
d667 1
a667 1
            user.setDomainId(domain.getDomainId());
d855 1
a855 1
                List domains = DomainPeer.doSelect(HelmPeer.NO_CRITERIA);
d1220 1
a1220 1
        List roles = new Host().getRequestableProjectRoles();
d1409 1
a1409 10
        grantRole(acl, role, ProjectPeer.getHostProject());
    }

    /**
     * Grants to this user the specified role in the domain.
     */
    public void grantRole(AccessControlList acl, Role role, Domain domain)
        throws ACLException, Exception
    {
        grantRole(acl, role, domain.getSpecialProject());
d1420 1
d1432 1
d1491 1
a1491 10
        revokeRole(acl, role, ProjectPeer.getHostProject());
    }

    /**
     * Revokes from this user a role in the given domain.
     */
    public void revokeRole(AccessControlList acl, Role role, Domain domain)
        throws ACLException, Exception
    {
        revokeRole(acl, role, domain.getSpecialProject());
d1548 1
a1548 1
        grantRole(root.getACL(), role, domain.getSpecialProject());
@


1.84
log
@Added reason for denying role requests and disapproving projects.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.83 2001/06/09 01:13:20 leonardr Exp $
d1173 2
a1174 1
     * Returns all non-special projects in which this user has a role..
d1180 1
a1180 1
        Criteria c = new Criteria()
d1185 1
d1190 1
a1190 1
     * Returns all projects in which this user has a role.
d1192 1
a1192 1
    public List getAllProjectsWithRole()
d1195 1
a1195 1
        Criteria c = new Criteria()
@


1.83
log
@Reinstated asGroup() methods as deprecated.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.82 2001/06/09 01:02:15 leonardr Exp $
d1272 1
a1272 1
                                   Role role, Project project)
d1279 4
d1363 1
a1363 1
                              role, project);
d1374 10
d1389 1
a1389 1
                          role, project);
@


1.82
log
@Got rid of the ugly and unneccessary asGroup() and getGroupInstance() methods.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.81 2001/06/07 03:13:00 dlr Exp $
d1552 13
@


1.81
log
@Fitted to line.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.80 2001/06/07 02:57:36 dlr Exp $
a382 15
    }

    /**
     * Turns a User object representing a group of users into a UserGroup
     * object.
     */
    public UserGroup asGroup()
        throws Exception
    {
        if (isBase())
        {
            throw new Exception
                ("Attempt to transform non-group user to UserGroup.");
        } 
        return UserPeer.getGroupInstance(getID());
@


1.80
log
@Switched to non-deprecated version of method.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.79 2001/06/06 16:42:44 edk Exp $
d1180 1
a1180 1
                (new Boolean(userEditSelfAllowsEditOrgProperty)).booleanValue())
@


1.79
log
@change name internally from UserEditAllows.. to UserEditSelfAllows.. --
which is more accurate
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.78 2001/06/06 16:13:37 edk Exp $
d490 1
a490 1
            .addOrderByColumn(NewsItemPeer.EVENT_DATE + " DESC");
@


1.78
log
@support for a new conf item (whose default is the current behavior)
to determine whether or not users can edit their own organizations
(if they don't have the User - Edit permission)
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.77 2001/06/05 18:53:08 leonardr Exp $
d747 1
a747 1
        if (!userEditAllowsEditOrganization() &&
d1174 1
a1174 1
    public static boolean userEditAllowsEditOrganization()
d1176 2
a1177 2
        String userEditAllowsEditOrgProperty = JoistProperties.getProperty(
                Domain.USER_EDIT_ALLOWS_EDIT_ORGANIZATION_KEY);
d1179 2
a1180 2
        if (userEditAllowsEditOrgProperty != null &&
                (new Boolean(userEditAllowsEditOrgProperty)).booleanValue())
@


1.77
log
@Added more functionality for role deletion.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.76 2001/05/25 19:29:35 leonardr Exp $
d747 2
a748 3

        //User - Edit - Self is not sufficient to change organization.
        if (!acl.hasPermission("User - Edit", getDomain())) {
d1168 17
@


1.76
log
@Added protected method that doesn't do ACL checking.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.75 2001/05/25 16:43:13 leonardr Exp $
d1249 16
@


1.75
log
@.wm is now .vm
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.74 2001/05/23 01:50:13 dlr Exp $
d1385 12
a1398 2
        acl.getUser().assertRoleGrantPermission(project);

d1427 1
a1427 1
            mapping.setApprovedBy(acl.getUser().getUserId());
d1444 1
a1444 1
            AuditLog.logEvent(acl.getUser(), project, AUDIT_LOG_ON_ROLE_GRANT 
@


1.74
log
@Ported Helm from WebMacro to Velocity.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.73 2001/05/22 23:35:53 leonardr Exp $
d123 1
a123 1
        TemplateTool.getPathToMessageTemplate("UserRoleRequest.wm");
d130 1
a130 1
        TemplateTool.getPathToMessageTemplate("RequestedRoleApproved.wm");
d137 1
a137 1
        TemplateTool.getPathToMessageTemplate("RequestedRoleDenied.wm");
d144 1
a144 1
        TemplateTool.getPathToRemoteBrandingTemplate("welcome.wm");
@


1.73
log
@Removed obsolete comment.
@
text
@d51 1
a51 1
import org.apache.turbine.om.*;
a55 1
import org.apache.turbine.util.ParameterParser;
d57 1
a58 1
import org.apache.turbine.util.db.pool.DBConnection;
d61 1
a61 1
import org.apache.turbine.services.webmacro.TurbineWebMacro;
d65 1
a65 1
import org.webmacro.servlet.WebContext;
d83 1
a83 1
 * @@version $Id: User.java,v 1.72 2001/05/17 14:51:17 leonardr Exp $
d241 1
a241 1
    public boolean matchesIdentity(WebContext ctx)
d568 1
a568 1
    public void sendNewPasswordTicket (WebContext context, String subject, 
d574 2
a575 1
        String url = URL.schemeAndServer(context) + "/servlets/PasswordEdit";
d579 1
a579 1
        WebContext ctx = TurbineWebMacro.getContext();
d582 1
a582 1
        String body = TurbineWebMacro.handleRequest(ctx, template);
d708 1
a708 1
        WebContext ctx = TurbineWebMacro.getContext();
d717 1
a717 1
        String body = TurbineWebMacro.handleRequest(ctx, WELCOME_TMPL);
d1258 1
a1258 1
        WebContext ctx = TurbineWebMacro.getContext();
d1262 1
a1262 1
        String body = TurbineWebMacro.handleRequest(ctx, templateName);
d1320 1
a1320 1
        WebContext ctx = TurbineWebMacro.getContext();
d1324 1
a1324 1
        String body = TurbineWebMacro.handleRequest(ctx,
@


1.72
log
@Refactored a lot of code to get rid of the good-looking but very slow IssueTrackingAccount{Descriptor,Map} classes. Also cleaned up the script-running interface quite a bit.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.71 2001/05/11 19:38:55 leonardr Exp $
a172 2

        //TODO: Cache guest user (and superuser?)
@


1.71
log
@A Heartbreaking Patch of Staggering Genius: adds capacity (but no interface) for deeply nested projects, categories, and project groups. As a side effect, gets rid of the hacky special 'all public projects in domain' group. There are probably bugs in this, and some of those bugs are probably security holes, so watch out.
@
text
@a75 1
import org.tigris.helm.tool.task.IssueTrackingAccountDescriptor;
d84 1
a84 1
 * @@version $Id: User.java,v 1.70 2001/05/10 01:26:36 dlr Exp $
a979 23
     * Return the type of issue tracking account this user has in the
     * given project. Used by IssueTrackingAccountMap.
     */
    public String issueTrackingAccountType(Project project)
        throws Exception
    {
	AccessControlList acl = getACL();
	String type="";
	if (acl.hasPermission
            ("Project Issue Tracking - Configure", project))
        {
            type = "admin";
        } else if (acl.hasPermission
                   ("Project Issue Tracking - Change", project)) {
            type = "developer";
        } else if (acl.hasPermission
                   ("Project Issue Tracking - Submit", project)) {
            type = "observer";
        }
	return type;
    }

    /**
d1187 14
d1434 1
a1434 1
                HelmTask.rebuildIssueTracking(project);
d1493 1
a1493 1
            HelmTask.rebuildIssueTracking(project);
@


1.70
log
@The short site name will be shown instead of "SourceCast" in welcome messages (as specified in the properties file).  If the short site name is not available, the domain name will be used as a fallback.  If even that is not available, then the text "SourceCast" will be used.  This fixes helm.tigris.org IZ #3.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.69 2001/05/02 16:24:52 leonardr Exp $
d1524 1
a1524 1
        grantRole(root.getACL(), role, domain.getSpecialPublicProject());
@


1.69
log
@Fixed sorting.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.68 2001/05/02 08:11:04 dlr Exp $
d702 9
a710 1
        String subject = "Welcome to Sourcecast";
d722 1
a722 1
        emailer.sendEmail(user.getEmail(), subject, body);
@


1.68
log
@Corrected getAttributes() call in Role and made use of HelmPeer's new NO_CRITERIA constant.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.67 2001/04/30 18:19:24 leonardr Exp $
d494 1
a494 1
            .addOrderByColumn(NewsItemPeer.HEADLINE + " DESC");
@


1.67
log
@Removed debugging.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.66 2001/04/20 21:19:40 leonardr Exp $
d857 1
a857 1
                List domains = DomainPeer.doSelect(new Criteria(0));
@


1.66
log
@Send CacheInvalidationEvents on deletes, and on saves of objects which are not themselves cached but which invalidate other caches when they are changed.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.65 2001/04/12 20:40:40 leonardr Exp $
a1494 1
            Log.debug("Redoing issue tracking.");
@


1.65
log
@Added toString()
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.64 2001/04/11 17:42:12 leonardr Exp $
a932 1
        UserPeer.uncache(this);
d1529 1
a1529 1
        UserPeer.uncache(this);
@


1.64
log
@Reworked PasswordEdit and got rid of the practice of generating passwords for new users. New users now get a ticket into PasswordEdit to set their passwords initially.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.63 2001/04/09 23:44:44 leonardr Exp $
d176 17
@


1.63
log
@Rebuild issue tracking when revoking roles as well as granting them.
@
text
@d69 1
d85 1
a85 1
 * @@version $Id: User.java,v 1.62 2001/04/05 02:20:50 leonardr Exp $
a543 1
        // TODO: Assure failure on database NULL.
d548 24
d759 38
d802 1
a802 1
                save();
d804 2
a805 1
            else {
d1479 1
@


1.62
log
@Always allow users to revoke their own roles.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.61 2001/04/04 00:44:29 leonardr Exp $
d1403 2
d1413 5
@


1.61
log
@Fixed problem that was causing duplicate news items to show up in a list.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.60 2001/04/03 09:27:28 manoj Exp $
d1100 1
a1100 1
            //Users may revoke their own roles.
d1389 6
a1394 2
        acl.getUser().assertRoleGrantPermission(project);

@


1.60
log
@Change the IdentityVerificationService to use a WebContext, so it can
grab information from places like the servlet request.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.59 2001/03/30 00:25:57 leonardr Exp $
d469 1
d476 23
a498 3
            .addOrderByColumn(NewsItemPeer.HEADLINE + " DESC")
            .setLimit(10);
        return NewsItemPeer.doSelect(c);        
@


1.59
log
@Factored out messages into constants, and used message in another place.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.58 2001/03/29 22:13:34 leonardr Exp $
a157 5
     * An additional identifier of this user (i.e. X509 cert, etc.).
     */
    private Object ident;

    /**
a219 10
     * Sets the cert for this user (i.e. X509, etc.).
     *
     * @@param ident The authorization certification for this user.
     */
    public void setIdentity(Object ident)
    {
        this.ident = ident;
    }

    /**
d227 1
a227 1
    public boolean matchesIdentity(Object ident)
d235 1
a235 1
            match = idVerifier.verify(this, ident);
@


1.58
log
@Actually save the new value, and give it the right new value.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.57 2001/03/29 05:22:29 edk Exp $
d1210 1
a1210 1
            throw new Exception("Your ticket is no longer valid");
d1215 1
a1215 1
            throw new Exception ("Your ticket is not valid for this project.");
@


1.57
log
@remove debugging breadcrumbs
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.56 2001/03/29 04:50:37 edk Exp $
d523 1
d525 2
a526 3
        // NOTE: This implementation looks fishy...I'm worried the string
        // "NULL" will be the value used, rather than SQL NULL.
        setPasswordTicket("NULL");
@


1.56
log
@consolidate logic for changing email addresses, and handle the case
where the user's domain is the host
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.55 2001/03/28 23:08:00 leonardr Exp $
a748 2
        Log.error("in setEmailAnzu, domain " + domain);
        Log.error("domain name is " + domain.getName());
a777 1
                    Log.error("one of the domains is : "+nextDomain.getName());
@


1.55
log
@Frontported change to RC1 branch.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54 2001/03/22 01:27:54 dlr Exp $
a620 1
        MailingAliasSpec alias = null;
d623 1
a623 12
            try 
            {
                alias = new MailingAliasSpec(domain.getName(),
                                             ProjectPeer.DEFAULT_PROJECT_NAME,
                                             loginName);
                alias.setDestination(email);
                alias.create();
            }
            catch (Exception e) 
            {
                throw new TaskException(e);
            }
d646 1
a646 7
                //try 
                //{
                    alias.delete();
                    //}
                //catch ( he) {
                //Log.error("Error attempting to delete alias for " 
                //+ user.getLoginName() + " as part of rollback.", e);
d688 6
a693 11
        if (!email.equals(getEmail())) {
            try {
                Domain domain = getDomain();
                String loginName = getLoginName();
                MailingAliasSpec alias =
                    new MailingAliasSpec(domain.getName(),"www",loginName);
                alias.setDestination(email);
                alias.update();
            } catch (Exception e) { // Domain constructor throws this ... bleah
                throw new TaskException(e);
            }
d741 72
d845 1
a845 7
        try {            
            MailingAliasSpec alias =
                new MailingAliasSpec(domain.getName(), "www", loginName);
            alias.delete();
        } catch (Exception e) {
            throw new TaskException(e);
        }              
@


1.54
log
@Renamed setIdent() to setIdentity() to better correspond to
matchesIdentity() and IdentityVerificationService.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.53 2001/03/22 01:24:43 leonardr Exp $
a1155 2
        //TODO: If a user has an invitation, bypass this
        //permission check.
d1157 31
@


1.54.2.1
log
@Role requests using tickets were doing an ACL check instead of using the tickets. This is fixed now.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54 2001/03/22 01:27:54 dlr Exp $
d1156 2
a1158 31
        requestRoleWithoutCheck(role, project);
    }

    /**
     * Requests for this user the specified role in the specified project,
     * burning the specified ticket in leiu of an ACL check.
     */
    public void requestRole(String ticket, Role role, Project project)
        throws Exception
    {
        Invitation invitation = InvitationPeer.getInstance(ticket);
        if (invitation == null)
        {
            throw new Exception("Your ticket is no longer valid");
        }

        if (!invitation.isMatch(project))
        {            
            throw new Exception ("Your ticket is not valid for this project.");
        }
        
        requestRoleWithoutCheck(role, project);
        invitation.delete();
    }

    /**
     * Requests for this user the specified role in the specified project.
     */
    private void requestRoleWithoutCheck(Role role, Project project)
        throws ACLException, Exception
    {
@


1.54.2.2
log
@consolidate logic for changing email addresses, and handle the case
where the user's domain is the host
Submitted by:   Ed Korthof <edk@@collab.net>
Reviewed by:    Leonard Richardson <leonardr@@collab.net>
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.1 2001/03/28 19:22:27 leonardr Exp $
d621 1
d624 12
a635 1
            setEmailAnzu(domain, loginName, email, true);
d658 7
a664 1
                deleteEmailAnzu(domain, loginName);
d706 11
a716 6
        // TODO : this should really go in the setEmail method ... but
        // Torque's generated factory methods -- in UserPeer.row2object --
        // would call it, which would be bad. -edk
        if (!email.equals(getEmail()) && getType().equals(REGULAR_TYPE))
        {
            setEmailAnzu(getDomain(), getLoginName(), email, false);
a763 72

    /**
     * This method sets the email address on the anzu server.  It handles
     * host level users specially ...
     */
    private static void setEmailAnzu(Domain domain, String loginName,
            String email, boolean create) throws Exception
    {
        Log.error("in setEmailAnzu, domain " + domain);
        Log.error("domain name is " + domain.getName());
        try
        {
            if (!domain.isHost())
            {
                MailingAliasSpec alias = new MailingAliasSpec(domain.getName(), 
                        ProjectPeer.DEFAULT_PROJECT_NAME, loginName);
                alias.setDestination(email);
                if (create)
                    alias.create();
                else
                    alias.update();
            }
            else
            {
                // do the above for each domain.  we could combine the two
                // if we constructed a container ... but that's unnecessary
                // object instanciation in the most common case.  probably
                // anzu should have a concept of host level items like this...
                //
                // TODO put a method in Domain to allow client code to
                // get the list of all domains.  that won't be necessary if
                // anzu is changed as above.
                List domains = DomainPeer.doSelect(new Criteria(0));
                Iterator i = domains.iterator();
                while(i.hasNext())
                {
                    Domain nextDomain = (Domain)i.next();
                    if (nextDomain.isHost())
                        continue;
                    Log.error("one of the domains is : "+nextDomain.getName());
                    MailingAliasSpec alias =
                        new MailingAliasSpec(nextDomain.getName(), 
                                ProjectPeer.DEFAULT_PROJECT_NAME, loginName);
                    alias.setDestination(email);
                    if (create)
                        alias.create();
                    else
                        alias.update();
                }
            }
        }
        catch (Exception e)
        {
            throw new TaskException(e);
        }
    }

    /**
     * This method deletes the email address on the anzu server.  It
     * handles host level users specially...
     */
    private static void deleteEmailAnzu(Domain domain, String loginName)
        throws TaskException
    {
        try {            
            MailingAliasSpec alias =
                new MailingAliasSpec(domain.getName(), "www", loginName);
            alias.delete();
        } catch (Exception e) {
            throw new TaskException(e);
        }              
    }
d796 7
a802 1
        deleteEmailAnzu(domain, loginName);
@


1.54.2.3
log
@remove debugging breadcrumbs
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.2 2001/03/29 04:52:00 edk Exp $
d749 2
d780 1
@


1.54.2.4
log
@Merging in Leonard's fix to HEAD.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.3 2001/03/29 05:21:59 edk Exp $
d524 3
a526 2
        setPasswordTicket(null);
        save();
@


1.54.2.5
log
@save() throws an instance of Exception that clearPasswordTicket() now
needs to propogate.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.4 2001/03/29 22:18:35 dlr Exp $
a522 1
        throws Exception
@


1.54.2.6
log
@Merging in Leonard's bug fix to the HEAD which prevents duplicate news
items to show up in a list (IZ #3804).
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.5 2001/03/30 09:54:50 dlr Exp $
a483 1
        int limit = 10;
d490 3
a492 23
            .addOrderByColumn(NewsItemPeer.HEADLINE + " DESC");

        c.setDistinct();

        //NOTE: This may not be exactly what we want, since news items
        //we've suggested that haven't yet been approved will show up
        //in isViewableBy, and we might not want that. But it's much closer
        //to what we want than what was here before.
        List potentials = NewsItemPeer.doSelect(c);        
        List actuals = new ArrayList(limit);
        for (Iterator i = potentials.iterator(); i.hasNext();)
        {
            NewsItem n = (NewsItem)i.next();
            if (n.isViewableBy(getACL()))
            {
                actuals.add(n);
                if (actuals.size() >= limit)
                {
                    break;
                }
            }
        }
        return actuals;
@


1.54.2.7
log
@Applied Manoj's HEAD change to IdentityVerificationService twiddlers.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.6 2001/04/04 01:04:52 dlr Exp $
d158 5
d225 10
d242 1
a242 1
    public boolean matchesIdentity(WebContext ctx)
d250 1
a250 1
            match = idVerifier.verify(this, ctx);
@


1.54.2.7.4.1
log
@Fixed sorting.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.7 2001/04/05 21:59:58 dlr Exp $
d476 1
a476 1
            .addOrderByColumn(NewsItemPeer.EVENT_DATE + " DESC");
@


1.54.2.7.4.2
log
@Backporting changes (reviewed by edk): The short site name will be shown instead of "SourceCast" in welcome messages (as specified in the properties file).  If the short site name is not available, the domain name will be used as a fallback.  If even that is not available, then the text "SourceCast" will be used.  This fixes helm.tigris.org IZ #3.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.7.4.1 2001/05/02 16:25:00 leonardr Exp $
d661 1
a661 9
        String shortSiteName = JoistProperties.getProperty(Domain.SHORT_SITE_NAME_KEY);
        if (!StringUtils.isValid(shortSiteName))
        {
            shortSiteName = JoistProperties.getProperty("DOMAIN");
            if (!StringUtils.isValid(shortSiteName))
            {
                shortSiteName = "SourceCast";
            }
        }
d673 1
a673 1
        emailer.sendEmail(user.getEmail(), "Welcome to " + shortSiteName, body);
@


1.54.2.7.4.3
log
@Use Project.rebuildIssueTracking rather than using an IssueTrackingAccountdescriptor.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.7.4.2 2001/05/10 02:10:26 dlr Exp $
a1128 14
        c.setDistinct();
        return ProjectPeer.doSelect(c);
    }

    /**
     * Returns all projects in which this user has a role.
     */
    public List getAllProjectsWithRole()
        throws Exception
    {
        Criteria c = new Criteria()
            .addJoin(UserRoleProjectPeer.PROJECT_ID,
                     ProjectPeer.PROJECT_ID)
            .add(UserRoleProjectPeer.USER_ID, getID());
@


1.54.2.7.4.4
log
@Recalculate issue tracking when someone loses a role.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.7.4.3 2001/05/16 00:29:28 leonardr Exp $
a1428 5

        if (role.affectsIssueTracking())
        {
            HelmTask.rebuildIssueTracking(project);
        }
@


1.54.2.7.4.5
log
@Ported task running system in from HEAD.
@
text
@d75 1
d84 1
a84 1
 * @@version $Id: User.java,v 1.54.2.7.4.4 2001/05/19 01:20:32 leonardr Exp $
d900 23
@


1.54.2.7.4.6
log
@Got rid of IssueTrackingRebuild task.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.54.2.7.4.5 2001/05/24 23:31:09 leonardr Exp $
d1355 1
a1355 1
                project.rebuildIssueTracking();
d1408 1
a1408 1
            project.rebuildIssueTracking();
@


1.53
log
@Throw AlreadyExists if the user already exists. How bout that.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.52 2001/03/22 01:09:26 dlr Exp $
d229 1
a229 1
    public void setIdent(Object ident)
@


1.52
log
@Added hooks for the new IdentityVerificationService.  This will allow
additional authorization checks to be performed, such as X509
certificates, etc.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.51 2001/03/20 16:42:05 leonardr Exp $
d198 1
a198 1
                                    "domain named " + domain.getName());
d552 1
a552 1
        throws ACLException, Exception
d563 1
a563 1
        throws ACLException, Exception
d576 1
a576 1
        throws ACLException, Exception
d589 1
a589 1
        throws ACLException, Exception
d602 1
a602 1
        throws ACLException, Exception
d616 1
a616 1
        throws ACLException, Exception
d618 3
@


1.51
log
@Added method for user self-registration.
@
text
@d61 1
d84 1
a84 1
 * @@version $Id: User.java,v 1.50 2001/03/16 02:46:52 elicia Exp $
d158 5
d222 35
@


1.50
log
@added isProjectOwner method
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.49 2001/03/13 19:08:00 leonardr Exp $
d550 27
d604 1
a604 1
            user.assertAddPermission(acl);
d846 1
a846 1
    public void assertAddPermission(AccessControlList acl)
d849 10
a858 2
        if (isBase()) {
            acl.assertPermission("User - Add", getDomain());
d860 2
a861 1
        else {
@


1.49
log
@Added a new type of task which redoes the issue tracking of a project. This causes some unneccessary scripts to be run (since we lose the context of how the issue tracking was before a change was made), but it lets us offload the time it takes to build an IssueTrackingAccountDescriptor onto the task-runner thread so that the user doesn't see it. The immediate performance effect (in the two places that now use the task instead of making their own ITADs) is to reduce user-visible project creation time from 10 seconds to 3 seconds (YMMV).
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.48 2001/03/13 03:53:01 dlr Exp $
d380 20
@


1.48
log
@* UserPeer's uncacheUser() was renamed to uncache().
* Noted why we uncache() in save().
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.47 2001/03/13 03:32:33 leonardr Exp $
a1162 5
            IssueTrackingAccountDescriptor before = null;
            if (rebuildIssueTracking)
            {
                before = new IssueTrackingAccountDescriptor(project, this);
            }
d1182 1
a1182 3
                IssueTrackingAccountDescriptor after = new
                    IssueTrackingAccountDescriptor(project, this);
                before.syncTo(after, acl.getUser());        
@


1.47
log
@Uncache the user upon deletion.
@
text
@d71 2
a77 2
import org.tigris.anzu.client.MailingAliasSpec;

d83 1
a83 1
 * @@version $Id: User.java,v 1.46 2001/03/13 03:15:03 leonardr Exp $
d716 1
a716 1
        UserPeer.uncacheUser(this);
d1262 3
a1264 1
     * Overrides BaseUser save to remove this user from the cache.
d1270 1
a1270 1
        UserPeer.uncacheUser(this);
@


1.46
log
@Implemented caching of users.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.45 2001/03/09 21:59:29 elicia Exp $
d716 1
a718 1

@


1.45
log
@added variable "canStartProject" to add method, for welcome message to new users
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.44 2001/03/08 03:30:42 dlr Exp $
d1259 10
@


1.44
log
@Pushed getID() method into base class as a final method.
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.43 2001/03/07 01:53:22 lucas Exp $
d586 6
@


1.43
log
@Corrected regex madness for Torque upgrade.  -dlr
@
text
@d83 1
a83 1
 * @@version $Id: User.java,v 1.42 2001/03/06 07:52:33 dlr Exp $
a215 12
    }

    //
    // Accessor methods for a particular user.
    //

    /**
     * Returns this user's ID as a string.
     */
    public final String getID()
    {
        return getPrimaryKey().toString();
@


1.42
log
@There has to be a variable in this context called "domainName".
@
text
@a68 2
import org.tigris.helm.om.peer.*;
import org.tigris.helm.om.base.*;
d83 1
a83 1
 * @@version $Id: User.java,v 1.41 2001/03/06 07:45:43 dlr Exp $
@


1.41
log
@It's a remote branding template.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.40 2001/03/06 04:04:53 elicia Exp $
d599 1
a599 1
        ctx.put("domain", domain.getName());
@


1.40
log
@added getNewsItemsForUser method
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.39 2001/03/06 00:31:39 leonardr Exp $
d117 2
a118 1
    private static final String AUDIT_LOG_ON_ROLE_REVOKE = "Role revoked from user: ";
d146 1
a146 1
        TemplateTool.getPathToBrandingTemplate("welcome.wm");
@


1.39
log
@Requested roles were being viewed as "already had" roles, so approval of them was failing.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.38 2001/03/05 19:28:22 leonardr Exp $
d428 19
d598 1
a598 1
        ctx.put("domainName", domain.getName());
@


1.38
log
@Grant the click-through role in the public domain projects so that private domain projects don't show up in the user's ACLDump and PermissionDump.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.37 2001/03/05 18:08:50 leonardr Exp $
d1124 1
a1124 1
        boolean alreadyHadRole = false;
d1139 4
a1142 1
            alreadyHadRole=true;
d1145 1
@


1.37
log
@Don't mail the user about granted requested role if they already had the role.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.36 2001/03/02 23:34:35 dlr Exp $
d1242 1
a1242 1
        grantRole(root.getACL(), role, domain);
@


1.36
log
@Switched order of welcome mail and audit log entry in main add()
method.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.35 2001/03/02 23:26:25 dlr Exp $
d1075 7
a1081 4
        grantRole(acl, role, project);
        mailUserAboutRole(ROLE_REQUEST_APPROVED_TEMPLATE,
                          "Requested role has been granted", 
                          role, project);
d1091 1
a1091 1
        //TODO: Throw an exception if the user hadn't requested this role?
d1119 1
d1121 1
a1121 1
    public void grantRole(AccessControlList acl, Role role, Project project)
d1124 1
d1139 1
a1142 13
        
        boolean rebuildIssueTracking = role.affectsIssueTracking();
        IssueTrackingAccountDescriptor before = null;
        if (rebuildIssueTracking)
        {
            before = new IssueTrackingAccountDescriptor(project, this);
        }

        mapping.setUserId(getUserId());
        mapping.setRoleId(role.getRoleId());
        mapping.setProjectId(project.getProjectId());
        mapping.setApprovedBy(acl.getUser().getUserId());
        mapping.save();
d1144 1
a1144 6
        // Invalidate the user's ACL.
        AccessControlList.rebuildACL(this);
        
        // People in charge of a project should have their names
        // names in a special alias -- owner@@{project}.{domain}
        if (role.denotesOwner() && role.getType().equals(Role.PROJECT_TYPE)) 
d1146 31
a1176 8
            AnzuTask.setOwnerAlias(this, project, true);
        }

        if (rebuildIssueTracking)
        {
            IssueTrackingAccountDescriptor after = new
                IssueTrackingAccountDescriptor(project, this);
            before.syncTo(after, acl.getUser());        
d1178 1
a1178 3
        AuditLog.logEvent(acl.getUser(), project, AUDIT_LOG_ON_ROLE_GRANT 
                          + getLoginName() + " <- " + role.getName());
                          
@


1.35
log
@Removed unused @@param.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.34 2001/03/02 23:14:04 dlr Exp $
d572 4
a575 1
        // Send welcome email message to new user
a583 2
        AuditLog.logEvent(acl.getUser(), domain, user.AUDIT_LOG_ON_ADD 
                          + user.getLoginName());
@


1.34
log
@Make use of a new TemplateTool method to retrive template paths from
files in $SANDBOX/site/org/joist/master (relative to Turbine template
root).  We should *never* be pulling directly from an INSTANCE's
source tree.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.33 2001/03/02 22:58:10 dlr Exp $
a182 1
     * @@param
@


1.33
log
@We're only using domain name, so I guess we can just supply that.
But let's name it more appropriately.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.32 2001/03/02 22:43:38 dlr Exp $
d145 1
a145 1
        JoistProperties.getProperty("BRAND_TEMPLATE_ROOT") + "/welcome.wm";
d170 2
a171 1
            throw new Error("Could not initialize regular expressions for user.");
@


1.32
log
@Let's just put the whole Domain object in the context.
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.31 2001/03/02 22:28:37 elicia Exp $
d576 1
a576 1
        ctx.put("domain", domain);
@


1.31
log
@added domain name to context when sending welcome message to new users
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.30 2001/03/02 21:40:14 dlr Exp $
d576 1
a576 1
        ctx.put("domain", domain.getName());
@


1.30
log
@The return value of getProperty() is a String, so no cast is needed
(nor would it be since another String object is being concatenated as
well).
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.29 2001/03/01 03:29:33 elicia Exp $
a574 1
        ctx.put("adminUser", acl.getUser());
d576 1
@


1.29
log
@add method sends out welcome message to new user
@
text
@d85 1
a85 1
 * @@version $Id: User.java,v 1.28 2001/02/27 23:29:13 leonardr Exp $
d145 1
a145 2
        (String) JoistProperties.getProperty("BRAND_TEMPLATE_ROOT") 
        +  "/welcome.wm";
@


1.28
log
@Don't change their password if they didn't specify a new one.
@
text
@d67 1
d85 1
a85 1
 * @@version $Id: User.java,v 1.27 2001/02/27 22:15:12 leonardr Exp $
d141 8
d572 9
@


1.27
log
@Made UserEdit host/domain role grant/revoke work.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.26 2001/02/27 09:13:55 dlr Exp $
d603 4
a606 1
        changePassword(acl, password, passwordConfirm);
d631 1
a631 1
        if (password != null && passwordConfirm != null) 
d633 2
a634 1
            if (password.equals(passwordConfirm)) {
@


1.26
log
@Make use of www project name constant.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.25 2001/02/27 03:28:03 dlr Exp $
d1131 1
a1131 1

d1195 1
a1195 1
        AuditLog.logEvent(acl.getUser(), project, AUDIT_LOG_ON_ROLE_GRANT 
@


1.25
log
@Only save() in changePassword() if the passwords match (rather than
every time, regardless of match).
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.24 2001/02/27 02:51:27 dlr Exp $
d521 3
a523 2
                alias =
                    new MailingAliasSpec(domain.getName(), "www", loginName);
@


1.24
log
@Added necessary JavaDoc of exceptions to changePassword() method.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.23 2001/02/26 23:35:02 leonardr Exp $
d630 2
a631 1
                if (password != null) setPassword(password);
a636 2
        setPassword(UserPeer.encryptPassword(password));
        save();
@


1.23
log
@When granting or revoking roles, invalidate the ACL afterwards.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.22 2001/02/26 22:03:25 leonardr Exp $
d618 3
@


1.22
log
@Almost got rid of dependance on hacky one-argument IssueTrackingAccountDescriptor.syncto().
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.21 2001/02/24 11:29:40 dlr Exp $
d1126 3
d1186 3
@


1.21
log
@Made use of the TurbineWebMacro facade around the
TurbineWebMacroService that supplies a convenience interface.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.20 2001/02/24 11:25:25 dlr Exp $
d516 5
a520 3
        if (type.equals(REGULAR_TYPE)) {
            try {
                MailingAliasSpec alias;
d526 2
a527 1
            catch (Exception e) {
d533 2
a534 1
        try {
d548 11
a558 11
        catch (Exception e) {
            if (type.equals(REGULAR_TYPE)) {
                //try {
                //alias.delete();
                //}
                //catch (HandlerException he) {
                //log.exception(he);
                //log.error("Error attempting to delete alias for " + userName +
                //" as part of rollback: " + he.getMessage());
                //}
                throw new TurbineException("Unable to finish creating User", e);
d560 1
d562 1
d692 2
a693 1
        try {
d696 2
a697 1
        catch (ACLException e) {
@


1.20
log
@Uncommented call to AnzuTask.setOwnerAlias().
@
text
@d61 1
a61 1
import org.apache.turbine.services.webmacro.WebMacroService;
d84 1
a84 1
 * @@version $Id: User.java,v 1.19 2001/02/24 11:18:09 dlr Exp $
d992 1
a992 3
        WebMacroService wmSrvc = (WebMacroService)
            TurbineServices.getInstance().getService(WebMacroService.SERVICE_NAME);
        WebContext ctx = wmSrvc.getContext();
d996 1
a996 1
        String body = wmSrvc.handleRequest(ctx, templateName);
d1024 2
a1025 4
        String subject = "New role requested.";
        WebMacroService wmSrvc = (WebMacroService)
            TurbineServices.getInstance().getService(WebMacroService.SERVICE_NAME);
        WebContext ctx = wmSrvc.getContext();
d1029 2
a1030 1
        String body = wmSrvc.handleRequest(ctx, ROLE_REQUESTED_TEMPLATE);
@


1.19
log
@Better JavaDoc for setClickThroughAsViewed().
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.18 2001/02/24 11:16:33 dlr Exp $
a1120 1
        // TODO: Uncomment.
d1125 1
a1125 1
            //AnzuTask.setOwnerAlias(this, project, true);
@


1.18
log
@Corrected comment mess.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.17 2001/02/24 04:08:58 dlr Exp $
d1187 5
a1191 1
     * Grants the "Click Through Viewer" role to a user.
@


1.17
log
@Removed uneeded local var.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.16 2001/02/24 03:28:51 dlr Exp $
d1187 2
a1188 2
     *      * Grants the "Click Through Viewer" role to a user.
     *           */
@


1.16
log
@This needs to throw Exception from because of the call to save().
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.15 2001/02/24 03:22:07 dlr Exp $
d627 1
a627 2
        String encrypted = UserPeer.encryptPassword(password);
        setPassword(encrypted);
@


1.15
log
@Save the password ticket after generating it.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.14 2001/02/23 19:09:51 leonardr Exp $
d436 1
@


1.14
log
@Get users using all avaliable methods.
@
text
@d51 1
a51 1
import org.apache.turbine.om.BaseObject;
d84 1
a84 1
 * @@version $Id: User.java,v 1.13 2001/02/23 17:01:11 leonardr Exp $
d220 1
a220 1
        return (String)getPrimaryKey();
d435 1
a435 1
    public String newPasswordTicket ()
d439 1
d446 1
a446 1
    public final void clearPasswordTicket ()
@


1.13
log
@This should duplicate pre-port functionality (which we can change later) and not give errors when you grant someone a role they already have.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.12 2001/02/23 03:03:31 leonardr Exp $
d829 10
@


1.12
log
@Amazingly, role revocations now work as well.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.11 2001/02/23 02:58:39 leonardr Exp $
d1034 1
a1034 17
        acl.getUser().assertRoleGrantPermission(project);

        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.ROLE_ID, role.getRoleId())
            .add(UserRoleProjectPeer.PROJECT_ID, project.getProjectId())
            .add(UserRoleProjectPeer.APPROVED_BY, 
                 UserPeer.getNobodyUser().getUserId());

        UserRoleProject mapping = (UserRoleProject)
            PeerTool.getFirstBO(UserRoleProjectPeer.doSelect(c),
                                "Requested " + role.getName() 
                                + " role for " + getLoginName() 
                                + " in project " + project.getName());
        mapping.setApprovedBy(acl.getUser().getUserId());
        mapping.save();

d1081 16
a1103 1
        UserRoleProject mapping = new UserRoleProject();
@


1.11
log
@Role approval works now. Also throws an exception if they hadn't requested the role in question. Maybe it should just grant the role instead?
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.10 2001/02/22 21:37:21 leonardr Exp $
d1166 2
a1167 2
            .add(UserRoleProjectPeer.ROLE_ID, getUserId())
            .add(UserRoleProjectPeer.PROJECT_ID, getUserId());
@


1.10
log
@Fixed password setting.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.9 2001/02/22 15:36:14 leonardr Exp $
d1034 16
a1049 2
        //TODO: Throw an exception if the user hadn't requested this role?
        grantRole(acl,role,project);
@


1.9
log
@Changed getProjectsForUser to use addJoin, get distinct entries, and not get host or domain projects.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.8 2001/02/22 02:39:42 leonardr Exp $
d532 1
a532 1
            user.setPassword(password); //FIXME
d593 2
a597 10
        if (password != null && passwordConfirm != null) {
            if (password.equals(passwordConfirm)) {
                // FIXME: Encrypt the password.
                // UserPeer.encryptPassword(String) could be used.
                //if (password != null) setPassword(password);
            }
            else {
                throw new Exception("Passwords did not match");
            }
        }
d615 13
a627 1
         update(acl, null, null, null, password, passwordConfirm);
d629 1
a629 1

@


1.8
log
@Standardized on User.getAvailableRolesInProject.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.7 2001/02/22 01:29:53 dlr Exp $
d905 1
a905 1
     * Returns all projects in which this user has a role..
d910 1
d912 5
a916 9
            .add(UserRoleProjectPeer.USER_ID, getID());
        List urps = UserRoleProjectPeer.doSelect(c);
        List projects = new ArrayList(urps.size());
        UserRoleProject urp;
        for (Iterator i = urps.iterator(); i.hasNext(); ) {
            urp = (UserRoleProject)i.next();
            projects.add(ProjectPeer.retrieveByPK(urp.getProjectId()));
        }
        return projects;
d918 6
a923 6

   /**
    * Returns all the requestable project roles which the user does
    * not currently posess (in granted or requested form) in the given
    * project
    */
@


1.7
log
@Find templates in the right place.
@
text
@d84 1
a84 1
 * @@version $Id: User.java,v 1.6 2001/02/22 00:38:46 dlr Exp $
d927 1
a927 1
    public List getAvaliableRolesInProject (Project project)
d930 5
a934 5
        List allRoles = new Host().getRequestableProjectRoles();
        List haveRoles = getRolesInProject(project);
        haveRoles.addAll(getRequestedRolesInProject(project));
        allRoles.removeAll(haveRoles);
        return allRoles;
@


1.6
log
@Now using TurbineWebMacroService instead of TemplateInterpolator.
@
text
@a70 2
import org.tigris.helm.tool.PeerTool;
import org.tigris.helm.tool.Nonce;
d72 1
a75 1
import org.tigris.helm.tool.*;
d84 1
a84 1
 * @@version $Id: User.java,v 1.5 2001/02/21 05:36:23 edk Exp $
a87 1

d123 1
a123 1
        "UserRoleRequest.wm";
d130 1
a130 1
        "RequestedRoleApproved.wm";
d137 1
a137 1
        "RequestedRoleDenied.wm";
@


1.5
log
@fix imports, exceptions, and use turbine logging
@
text
@d60 2
d65 1
a65 1
import org.webmacro.engine.BuildContext;
d86 1
a86 1
 * @@version $Id: User.java,v 1.4 2001/02/21 05:03:19 edk Exp $
d983 3
a985 1
        BuildContext ctx = TemplateInterpolator.createContext();
d989 1
a989 2
        String body = TemplateInterpolator.interpolate
            (templateName, ctx, getClass());
d1018 3
a1020 1
        BuildContext ctx = TemplateInterpolator.createContext();
d1024 1
a1024 2
        String body = TemplateInterpolator.interpolate
            (ROLE_REQUESTED_TEMPLATE, ctx, getClass());
@


1.4
log
@uncomment calls to set up the alias, and add a setClickThroughAsViewed
@
text
@d73 1
d77 2
d84 1
a84 1
 * @@version $Id: User.java,v 1.3 2001/02/21 04:38:18 dlr Exp $
d524 1
a524 3
                Log.error(e);
                Log.error("unable to setup email: " + e.getMessage());
                throw new UpdateException("Unable to setup e-mail alias");
d586 1
a586 6
                Log.error("unable to update email address for " + loginName +
                          ": " + e.getMessage());
                Log.error(e);
                // TODO : should we throw an exception?  this method should
                // really only throw UpdateException & ACLException ...
                // TaskException would be the right thing to throw.
d663 1
a663 3
            Log.error("unable to delete email address for " + getName() +
                      ": " + e.getMessage());
            Log.error(e);
@


1.3
log
@Password update changes.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.2 2001/02/21 03:02:22 edk Exp $
d513 12
a524 12
            // TODO: FIXME
            //try {
            //MailingAliasSpec alias;
            //alias = new MailingAliasSpec(domain.getName(), "www", userName);
            //alias.setDestination(email);
            //alias.create();
            //}
            //catch (Exception e) {
            //  log.exception(e);
            //  if (debug) log.error("unable to setup email: " + e.getMessage());
            //throw new UpdateException("Unable to setup e-mail alias");
            //}
d576 17
a592 16
//          if (!email.equals(getEmail())) {
//              try {
//                  Domain domain = new Domain(dMgr, getDomainID());
//                  MailingAliasSpec alias =
//                      new MailingAliasSpec(domain.getName(), "www", loginName);
//                  alias.setDestination(email);
//                  alias.update();
//              } catch (Exception e) { // Domain constructor throws this ... bleah
//                  log.error("unable to update email address for " + loginName +
//                            ": " + e.getMessage());
//                  log.exception(e);
//                  // TODO : should we throw an exception?  this method should
//                  // really only throw UpdateException & ACLException ...
//                  // TaskException would be the right thing to throw.
//              }
//          }
d642 1
d661 10
a670 10
//          // remove the Anzu alias
//          try {            
//              MailingAliasSpec alias =
//                  new MailingAliasSpec(domain.getName(), "www", getLoginID());
//              alias.delete();
//          } catch (Exception e) {
//              log.error("unable to delete email address for " + getName() +
//                        ": " + e.getMessage());
//              log.exception(e);
//          }              
a673 1
        String loginName = getLoginName();
d1164 11
@


1.2
log
@adding files from the branch to the head
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.1.1.1 2001/02/21 00:33:05 dlr Exp $
d513 1
d560 5
d594 1
a594 2
        if (!acl.hasPermission("User - Edit", getDomain()))
        {
d600 10
a609 1
        //if (password != null) setPassword(password); //FIXME
d616 11
a626 11
     /**
      * Updates the user's password.
      *
      * @@param passwd        The new password to use.
      * @@param passwdConfirm Confirmation of the new password.
      *
      */
     public void changePassword 
         (AccessControlList acl, String password, String passwordConfirm)
         throws ACLException, Exception
     {
d628 1
a628 1
     }
@


1.1
log
@file User.java was initially added on branch HELM_PEER_PORT_BRANCH.
@
text
@d1 1150
@


1.1.1.1
log
@Replacing the HEAD with the HELM_PEER_PORT_BRANCH.
@
text
@a0 1150
/* ================================================================
 * Copyright (c) 2000-2001 CollabNet.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if
 * any, must include the following acknowlegement: "This product includes
 * software developed by CollabNet (http://www.collab.net/)."
 * Alternately, this acknowlegement may appear in the software itself, if
 * and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@@collab.net.
 * 
 * 5. Products derived from this software may not use the "Tigris" name
 * nor may "Tigris" appear in their names without prior written
 * permission of CollabNet.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL COLLABNET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals on behalf of CollabNet.
 */

package org.tigris.helm.om;

import java.util.*;

import org.apache.turbine.om.BaseObject;
import org.apache.turbine.om.peer.BasePeer;
import org.apache.turbine.util.db.Criteria;
import org.apache.turbine.util.ObjectUtils;
import org.apache.turbine.util.StringUtils;
import org.apache.turbine.util.ParameterParser;
import org.apache.turbine.util.Log;
import org.apache.turbine.util.TurbineException;
import org.apache.turbine.util.db.pool.DBConnection;

import gnu.regexp.*;

import org.webmacro.engine.BuildContext;

import org.tigris.helm.*;
import org.tigris.helm.om.peer.*;
import org.tigris.helm.om.base.*;
import org.tigris.helm.security.*;
import org.tigris.helm.tool.PeerTool;
import org.tigris.helm.tool.Nonce;

import org.tigris.helm.tool.task.IssueTrackingAccountDescriptor;
import org.tigris.helm.tool.audit.AuditLog;
import org.tigris.helm.tool.*;

/** 
 * User business object.
 *
 * @@author <a href="mailto:leonardr@@collab.net">Leonard Richardson</a>
 * @@author <a href="mailto:dlr@@collab.net">Daniel Rall</a>
 * @@version $Id: User.java,v 1.1.2.56 2001/02/17 00:19:31 leonardr Exp $
 */
public class User extends BaseUser implements UserType, Comparable
{

    /**
     * Description of the audit log entry created when a user of this
     * type is added.  
     */
    private static final String AUDIT_LOG_ON_ADD = "User added: ";

    /**
     * Description of the audit log entry created when a user of this
     * type is deleted.
     */
    private static final String AUDIT_LOG_ON_DELETE = "User deleted: ";

    /**
     * Description of the audit log entry created when a user of this
     * type is edited.
     */
    private static final String AUDIT_LOG_ON_EDIT = "User edited: ";

    /**
     * Description of the audit log entry created when a user of this
     * type is granted a role.
     */
    private static final String AUDIT_LOG_ON_ROLE_GRANT = "Role granted to user: ";

    /**
     * Description of the audit log entry created when a role is
     * revoked from a user of this type.  
     */
    private static final String AUDIT_LOG_ON_ROLE_REVOKE = "Role revoked from user: ";

    /**
     * The name of the template used to create the body of the user role 
     * request email.
     */
    private static final String ROLE_REQUESTED_TEMPLATE = 
        "UserRoleRequest.wm";

    /**
     * The name of the template used to create the body of the requested
     * role approval email.
     */
    private static final String ROLE_REQUEST_APPROVED_TEMPLATE = 
        "RequestedRoleApproved.wm";

    /**
     * The name of the template used to create the body of the requested
     * role denial email.
     */
    private static final String ROLE_REQUEST_DENIED_TEMPLATE = 
        "RequestedRoleDenied.wm";

    /**
     * The regular expression used to validate login names.
     */
    private static RE loginNameRE;

    /**
     * The regular expression used to validate real names.
     */
    private static RE realNameRE;

    /**
     * Static initializer; initialize regular expressions.
     */
    static
    {
        try
        {
            // HELP: Are these things thread safe?
            loginNameRE = new RE("^[\\w]{1,16}$");
            realNameRE = new RE("^[\\w' \\-\\.\\,\\(\\)]+$");
        }
        catch (REException e)
        {
            throw new Error("Could not initialize regular expressions for user.");
        }

        //TODO: Cache guest user (and superuser?)
    }

    /**
     * Throws an exception if the specified information corresponds to an
     * existing user.
     *  
     * @@param domain    The domain to check.
     * @@param loginName The login name of the user to search for.
     * @@param
     */
    public static void assertNonexistance(Domain domain, String loginName)
        throws AlreadyExists, Exception
    {
        Criteria c = new Criteria()
            .add(UserPeer.LOGIN_NAME, loginName);
        UserPeer.checkThisAndHostDomain(c, domain);
        List u = UserPeer.doSelect(c);
        if (!u.isEmpty()) {
            throw new AlreadyExists("User with loginName of " + loginName,
                                    "domain named " + domain.getName());
        }
    }

    /**
     * Checks whether a login name is valid.
     *
     * @@param loginName The login name to check.
     * @@return          Whether the name is valid.
     */
    public static boolean isValidLoginName (String loginName)
    {
        return (loginName != null && loginNameRE.isMatch(loginName));
    }

    /**
     * Checks whether a real name is valid.
     *
     * @@param realName The real name to check.
     * @@return         Whether the name is valid.
     */
    public static boolean isValidRealName (String realName)
    {
        return (realName != null && realNameRE.isMatch(realName));
    }

    //
    // Accessor methods for a particular user.
    //

    /**
     * Returns this user's ID as a string.
     */
    public final String getID()
    {
        return (String)getPrimaryKey();
    }

    /**
     * Returns the ID of this user's domain as a string.
     */
    public final String getDomainID()
    {
        return String.valueOf(getDomainId());
    }

    /**
     * Returns the site email address for this user.
     */
    public String getDomainEmail()
        throws Exception
    {
        String domName = getDomain().getName();
        return getLoginName() + "@@" + domName;
    } 

    /**
     * Returns true iff this user represents the users in a domain.
     */
    public boolean isDomain()
    {
        return (this instanceof DomainUserGroup);
    }

    /**
     * Returns true iff this user represents the users in the host domain.
     */    
    public boolean isHost()
    {
        return (this instanceof HostUserGroup);
    }

    /**
     * Returns true iff this user represents an admin-defined usergroup.
     */
    public boolean isGroup()
    {
        return (this instanceof UserGroup);
    }

    /**
     * Returns true iff this User object represents an actual user of
     * the site who can log in.  
     */
    public boolean isBase()
        throws Exception
    {
        //TODO: Check for other special accounts like postmaster, etc.
        return (!isGroup() && !isNobody());
    }

    /**
     * Determines whether the user is the application's guest user.  Useful in
     * WebMacro template code.
     *
     * @@return Whether the guest user.
     */
    public final boolean isAnonymous()
        throws Exception
    {
        return equals(UserPeer.getAnonymousUser());
    }
 
   /**
     * Determines whether the user is the special "nobody" user.
     *
     * @@return Whether the special "nobody".
     */
    public final boolean isNobody()
        throws Exception
    {
        return equals(UserPeer.getNobodyUser());
    }

    /**
     * Determines whether the user is the superuser.
     *
     * @@return Whether the superuser.
     */
    public final boolean isSuperUser()
        throws Exception
    {
        return equals(UserPeer.getSuperUser());
    }

    /**
     * @@deprecated Use isAnonymous() instead.
     */
    public final boolean isGuest()
        throws Exception
    {
        return isAnonymous();
    }

    /**
     * Compare this user to another object for sorting purposes.
     */
    public int compareTo(Object o)
        throws ClassCastException
    {
        User u = (User)o;
        return getRealName().compareTo(u.getRealName());
    }

    /**
     * Forces a rebuild of the ACL for this user. Calling it on a
     * UserGroup will rebuild the ACLs of everyone in the UserGroup.
     */
    public void rebuildACL()
        throws Exception
    {
        for (Iterator i = expand().iterator(); i.hasNext(); ) {
            AccessControlList.rebuildACL((User)i.next());
        }
    }

    /**
     * Obtains the ACL for this user.
     */
    public AccessControlList getACL()
        throws Exception
    {
        return AccessControlList.getACL(this);
    }

    /**
     * Turns a User object representing a group of users into a UserGroup
     * object.
     */
    public UserGroup asGroup()
        throws Exception
    {
        if (isBase())
        {
            throw new Exception
                ("Attempt to transform non-group user to UserGroup.");
        } 
        return UserPeer.getGroupInstance(getID());
    }

    /**
     * Returns a list of the effective user IDs for this user. This
     * consists of the user's ID itself and ther user IDs of all groups
     * to which this user belongs.
     */
    public List effectiveUserIDs()
        throws Exception
    {
        Criteria c = new Criteria().add(UserUsergroupPeer.USER_ID,getID());
        List mappings = UserUsergroupPeer.doSelect(c);
        List myIDs = new ArrayList(mappings.size()+1);
        myIDs.add(getID());
        for (Iterator i = mappings.iterator(); i.hasNext();)
        {
            UserUsergroup g = (UserUsergroup)i.next();
            myIDs.add(g.getUserGroupID());
        }
        return myIDs;
    }
    
    /**
     * Return a list of all groups to which this user belongs, not including
     * the special domain group.
     */
    public List getRegularGroups()
        throws Exception
    {
        List groups = getGroups();
        //There will probably be one fewer entry in the new list than
        //in the old, since every user belongs to one special group.
        List newGroups = new ArrayList(groups.size()-1);
        for (Iterator i = groups.iterator(); i.hasNext();)
        {
            User u = (User)i.next();
            if (!(u.isDomain() || u.isHost()))
            {
                newGroups.add(u);
            }
        }
        return newGroups;
    }

    /**
     * Return a list of all groups to which this user belongs, including
     * the special domain group.
     */
    public List getGroups()
        throws Exception
    {
        Criteria c = new Criteria()
            .addJoin(UserUsergroupPeer.USER_GROUP_ID, UserPeer.USER_ID)
            .add(UserUsergroupPeer.USER_ID,getID());
        return UserPeer.doSelect(c);        
    }

    /**
     * Returns a list of Users represending all the users this user represents.
     * If called on a base user, returns a list containing only itself.
     */    
    public List expand()
        throws Exception
    {
        List users = new ArrayList(1);
        users.add(this);
        return users;
    }

    /**
     * Creates and saves a new password ticket.
     */
    public String newPasswordTicket ()
    {
        String ticket = Nonce.buildNonce();
        setPasswordTicket(ticket);
        return ticket;
    }

    /**
     * Removes a used password ticket.
     */
    public final void clearPasswordTicket ()
    {
        // NOTE: This implementation looks fishy...I'm worried the string
        // "NULL" will be the value used, rather than SQL NULL.
        setPasswordTicket("NULL");
    }

    /**
     * Determines whether the password ticket is valid.
     *
     * @@param ticket The ticket to compare.
     */
    public boolean isValidPasswordTicket (String ticket)
        throws Exception
    {
        // TODO: Assure failure on database NULL.
        return (ticket != null && 
                ticket.equals(getPasswordTicket()));
    }

    //
    // Mutator methods
    //

    /**
     * Adds a new base user.
     */
    public static User add
        (AccessControlList acl, Domain domain, String realName, 
         String loginName, String type)
        throws ACLException, Exception
    {
        return add(acl, domain, realName, loginName, null, null, null, type);
    }

    /**
     * Adds a new base user.
     */
    public static User add
        (AccessControlList acl, Domain domain, String realName,
         String loginName, String password, String email)
        throws ACLException, Exception
    {
        User u = add(acl, domain, realName, loginName, password, email, null, 
                     REGULAR_TYPE);
        return u;
    }

    /**
     * Adds a new base user.
     */
    public static User add 
        (AccessControlList acl, Domain domain, String realName,
         String loginName, String password, String email, String organization)
        throws ACLException, Exception
    {
        return add(acl, domain, realName, loginName, password, email,
                   organization, REGULAR_TYPE);
    }

    /**
     * Adds a new user of the specified type. 
     */
    public static User add 
        (AccessControlList acl, Domain domain, String realName,
         String loginName, String password, String email, String organization,
         String type)
        throws ACLException, Exception
    {
        if (type.equals(REGULAR_TYPE)) {
            //try {
            //MailingAliasSpec alias;
            //alias = new MailingAliasSpec(domain.getName(), "www", userName);
            //alias.setDestination(email);
            //alias.create();
            //}
            //catch (Exception e) {
            //  log.exception(e);
            //  if (debug) log.error("unable to setup email: " + e.getMessage());
            //throw new UpdateException("Unable to setup e-mail alias");
            //}
        }

        User user = new User();
        try {
            user.setDomainId(domain.getDomainId());
            user.setRealName(realName);
            user.setLoginName(loginName);
            user.setPassword(password); //FIXME
            user.setEmail(email);
            user.setOrganization(organization);
            user.setType(type);
            user.assertAddPermission(acl);
            user.save();

            //Add the user to the appropriate user group.
            user.addToDomainGroup();
        }
        catch (Exception e) {
            if (type.equals(REGULAR_TYPE)) {
                //try {
                //alias.delete();
                //}
                //catch (HandlerException he) {
                //log.exception(he);
                //log.error("Error attempting to delete alias for " + userName +
                //" as part of rollback: " + he.getMessage());
                //}
                throw new TurbineException("Unable to finish creating User", e);
            }
        }
        AuditLog.logEvent(acl.getUser(), domain, user.AUDIT_LOG_ON_ADD 
                          + user.getLoginName());
        return user;
    }

    public void update(AccessControlList acl, String email, 
                       String realName, String organization, 
                       String password, String passwordConfirm)
        throws ACLException, Exception
    {
        if (!password.equals(passwordConfirm))
        {
            throw new Exception("Passwords do not match.");
        }
        assertEditPermission(acl);
        
//          if (!email.equals(getEmail())) {
//              try {
//                  Domain domain = new Domain(dMgr, getDomainID());
//                  MailingAliasSpec alias =
//                      new MailingAliasSpec(domain.getName(), "www", loginName);
//                  alias.setDestination(email);
//                  alias.update();
//              } catch (Exception e) { // Domain constructor throws this ... bleah
//                  log.error("unable to update email address for " + loginName +
//                            ": " + e.getMessage());
//                  log.exception(e);
//                  // TODO : should we throw an exception?  this method should
//                  // really only throw UpdateException & ACLException ...
//                  // TaskException would be the right thing to throw.
//              }
//          }

        //User - Edit - Self is not sufficient to change organization.
        if (!acl.hasPermission("User - Edit", getDomain()))
        {
            organization = getOrganization();
        }
         
        if (realName != null) setRealName(realName);
        if (email != null) setEmail(email);
        //if (password != null) setPassword(password); //FIXME
        if (organization != null) setOrganization(organization);
        AuditLog.logEvent(acl.getUser(), getDomain(), AUDIT_LOG_ON_EDIT
                          + getLoginName());
        save();         
    }
    
     /**
      * Updates the user's password.
      *
      * @@param passwd        The new password to use.
      * @@param passwdConfirm Confirmation of the new password.
      *
      */
     public void changePassword 
         (AccessControlList acl, String password, String passwordConfirm)
         throws ACLException, Exception
     {
         update(acl, null, null, null, password, passwordConfirm);
     }

    /**
     * Deletes the corresponding user record from the database.
     *
     * @@param acl The ACL of the user performing the delete.
     *
     * @@exception Exception Likely a database error.
     */
    public void delete(AccessControlList acl)
        throws ACLException, Exception
    {
        Domain domain = getDomain();
        assertDeletePermission(acl);

        User deletingUser = acl.getUser();
        //Remove the user from all composite users.
        for (Iterator i = getGroups().iterator(); i.hasNext();)
        {
            UserGroup u = (UserGroup)i.next();
            removeFromGroup(acl, u);
        }               

        //Revoke all the user's roles, requested or granted.
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId());
        UserRoleProjectPeer.doDelete(c);
        // Having deleted the user from individual projects, delete
        // the user from the domain.  Mostly affects Issuezilla.
        HelmTask.deleteUser(deletingUser, domain, this);

//          // remove the Anzu alias
//          try {            
//              MailingAliasSpec alias =
//                  new MailingAliasSpec(domain.getName(), "www", getLoginID());
//              alias.delete();
//          } catch (Exception e) {
//              log.error("unable to delete email address for " + getName() +
//                        ": " + e.getMessage());
//              log.exception(e);
//          }              

        //Remove the user proper.
        String message = AUDIT_LOG_ON_DELETE;
        String loginName = getLoginName();
        UserPeer.doDelete(new Criteria().add(UserPeer.USER_ID, getID()));

        AuditLog.logEvent(acl.getUser(), getDomain(), message + loginName);

     }

    //
    // Group management
    //

    public void addToDomainGroup()
        throws Exception
    {
        AccessControlList acl = AccessControlList.getSuperUserACL();
        try {
            UserPeer.getDomainUser(getDomain()).addUser(acl, this);        
        }
        catch (ACLException e) {
            throw new Error
                ("Super user lacks permission to add user to group.");
        }
    }

    public void addToGroup(AccessControlList acl, UserGroup g)
        throws ACLException, Exception
    {
        g.addUser(acl, this);
    }

    public void removeFromGroup(AccessControlList acl, UserGroup g)
        throws ACLException, Exception
    {
        g.removeUser(acl, this);
    }

    //
    // Role and permission management - accessor methods
    //

    /**
     * Return the type of issue tracking account this user has in the
     * given project. Used by IssueTrackingAccountMap.
     */
    public String issueTrackingAccountType(Project project)
        throws Exception
    {
	AccessControlList acl = getACL();
	String type="";
	if (acl.hasPermission
            ("Project Issue Tracking - Configure", project))
        {
            type = "admin";
        } else if (acl.hasPermission
                   ("Project Issue Tracking - Change", project)) {
            type = "developer";
        } else if (acl.hasPermission
                   ("Project Issue Tracking - Submit", project)) {
            type = "observer";
        }
	return type;
    }

    /**
     * Returns true iff this user is visible by the given ACL.
     */
    public final boolean isViewableBy (AccessControlList acl)
        throws Exception
    {
        boolean viewable = false;
        if (acl.hasPermission("User - View", getDomain())
            || (acl.getUser().getID().equals(getID()) &&
                acl.hasPermission("User - View - Self", getDomain())))
        {
            viewable = true;
        }
        return viewable;
    }

    /**
     * Throws an exception unless the user has permission sufficient to
     * add this user to the database.
     */
    public void assertAddPermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (isBase()) {
            acl.assertPermission("User - Add", getDomain());
        }
        else {
            acl.assertPermission("UserGroup - Add", getDomain());
        }
    }

    /**
     * Throws an exception unless the user has permission sufficient to
     * delete this user.
     */
    public void assertDeletePermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (isBase()) {
            acl.assertPermission("User - Delete", getDomain());
        }
        else {
            acl.assertPermission("UserGroup - Delete", getDomain());
        }
    }

    /**
     * Returns true iff the user has permission sufficient to delete
     * this user.  
     */
    public boolean hasDeletePermission(AccessControlList acl)
        throws Exception
    {
        boolean ok = false;
        if (isBase()) {
            ok = acl.hasPermission("User - Delete", getDomain());
        }
        else {
            ok = acl.hasPermission("UserGroup - Delete", getDomain());
        }
        return ok;
    }

    /**
     * Throw an exception unless the provided ACL has permission sufficient
     * to edit this user's information.
     */
    public void assertEditPermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (!isEditableBy(acl))
        {
            throw new ACLException(acl, "User edit permission", 
                                   "Domain " + getDomain().getName(), null);
        }
    }

    /**
     * Returns true iff the provided ACL has permission sufficient to
     * edit this user's information.
     */
    public boolean isEditableBy(AccessControlList acl)
        throws Exception
    {
        boolean ok = false;
        if (acl.getUserID().equals(getID()) &&
            acl.hasPermission("User - Edit - Self", getDomain()))
        {
            ok = true;
        }

        if (!ok && acl.hasPermission("User - Edit", getDomain()))
        {
            ok = true;
        }
        return ok;
    }

    /**
     * Returns true iff the user has requested the given role in the
     * given project.  
     */
    public boolean hasRequestedRoleInProject(Role role, Project project)
        throws Exception
    {
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.ROLE_ID, getUserId())
            .add(UserRoleProjectPeer.PROJECT_ID, getUserId())
            .add(UserRoleProjectPeer.APPROVED_BY, 
                 UserPeer.getNobodyUser().getUserId());
        List roles = UserRoleProjectPeer.doSelect(c);
        return (!roles.isEmpty());
    }

    /**
     * Returns true iff the provided ACL has permission sufficient to
     * look at this user's information.  
     */
    public void assertViewPermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (acl.getUserID().equals(getID())) {
            acl.assertPermission("User - View - Self", getDomain());
        }
        else {
            acl.assertPermission("User - View", getDomain());
        }
    }

    /**
     * Throws an ACLException if this user cannot grant roles in the
     * given project.  Note that the grant permission implies revoke
     * as well.  
     */
    public void assertRoleGrantPermission (Project project)
        throws ACLException, Exception
    {
        getACL().assertPermission
            (project.requiredRoleGrantAction(), project);
    }

    /**
     * Returns true if this user can grant roles in the given
     * project.  Note that the grant permission implies revoke as
     * well.  
     */
    public boolean hasRoleGrantPermission (Project project)
        throws Exception
    {
        return getACL().hasPermission
            (project.requiredRoleGrantAction(), project);
    }

    /**
     * Returns true if this user can grant roles in the given
     * project.  Note that the grant permission implies revoke as
     * well.  
     */
    public boolean canRevokeRole(User user, Project project)
        throws Exception
    {
        boolean ok = false;
        if (user.getID().equals(getID()))
        {
            //Users may revoke their own roles.
            ok = true;
        } 
        else 
        {
            ok = hasRoleGrantPermission(project);
        }
        return ok;
    }

    /**
     * Returns all projects in which this user has a role..
     */
    public List getProjectsForUser()
        throws Exception
    {        
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getID());
        List urps = UserRoleProjectPeer.doSelect(c);
        List projects = new ArrayList(urps.size());
        UserRoleProject urp;
        for (Iterator i = urps.iterator(); i.hasNext(); ) {
            urp = (UserRoleProject)i.next();
            projects.add(ProjectPeer.retrieveByPK(urp.getProjectId()));
        }
        return projects;
    }

   /**
    * Returns all the requestable project roles which the user does
    * not currently posess (in granted or requested form) in the given
    * project
    */
    public List getAvaliableRolesInProject (Project project)
        throws Exception
    {
        List allRoles = new Host().getRequestableProjectRoles();
        List haveRoles = getRolesInProject(project);
        haveRoles.addAll(getRequestedRolesInProject(project));
        allRoles.removeAll(haveRoles);
        return allRoles;
    }

    /**
     * Returns all the roles which a user has been granted in a project.
     */
    public List getRolesInProject (Project project)
        throws Exception
    {
        return getRolesInProject(project, true);
    }

    /**
     * Returns all the roles which a user has requested in a project.
     */
    public List getRequestedRolesInProject (Project project)
        throws Exception
    {
        return getRolesInProject(project, false);
    }

    /**
     * Does the heavy lifting for the public getRolesInProject and
     * getRequestedRolesInProject.  
     */
    private List getRolesInProject (Project project, boolean approved)
        throws Exception
    {
        String matchType = approved?Criteria.NOT_EQUAL:Criteria.EQUAL;
        List roles = new ArrayList ();
        Criteria c = new Criteria()
            .addJoin(RolePeer.ROLE_ID, UserRoleProjectPeer.ROLE_ID)
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.PROJECT_ID, project.getProjectId())
            .add(UserRoleProjectPeer.APPROVED_BY, 
                 UserPeer.getNobodyUser().getUserId(), matchType);
        return RolePeer.doSelect(c);
    }

    /**
     * Convenience method to send email to a user regarding a role.
     */
    private void mailUserAboutRole(String templateName, String subject,
                                   Role role, Project project)
        throws Exception
    {
        BuildContext ctx = TemplateInterpolator.createContext();
        ctx.put("user", this);
        ctx.put("role", role);
        ctx.put("project", project);
        String body = TemplateInterpolator.interpolate
            (templateName, ctx, getClass());
        new HelmEmailer().mailUserFromSystem(this, subject, body.toString());
    }

    //
    // Role and permission management - mutator methods
    //

    /**
     * Requests for this user the specified role in the specified project.
     */
    public void requestRole(Role role, Project project)
        throws ACLException, Exception
    {
        AccessControlList acl = getACL();
        //TODO: If a user has an invitation, bypass this
        //permission check.
        acl.assertPermission("Project Role - Request", project);
        UserRoleProject mapping = new UserRoleProject();
        mapping.setUserId(getUserId());
        mapping.setRoleId(role.getRoleId());
        mapping.setProjectId(project.getProjectId());
        mapping.setApprovedBy(UserPeer.getNobodyUser().getUserId());
        mapping.save();

        //TODO: Add name to alias as per grantRole? (Such happens
        //in HEAD, but why?)

        String subject = "New role requested.";
        BuildContext ctx = TemplateInterpolator.createContext();
        ctx.put("user", this);
        ctx.put("role", role);
        ctx.put("project", project);
        String body = TemplateInterpolator.interpolate
            (ROLE_REQUESTED_TEMPLATE, ctx, getClass());
        HelmEmailer emailer = new HelmEmailer();
        emailer.messageUsersWithProjectOwnership
            (project, subject, body.toString());
    }

    /**
     * Approves an already requested role.
     */
    public void approveRole(AccessControlList acl, Role role, Project project)
        throws ACLException, Exception
    {        
        //TODO: Throw an exception if the user hadn't requested this role?
        grantRole(acl,role,project);

        mailUserAboutRole(ROLE_REQUEST_APPROVED_TEMPLATE,
                          "Requested role has been granted", 
                          role, project);
    }

    /**
     * Disapproves a requested role.
     */
    public void disapproveRole(AccessControlList acl, Role role, 
                               Project project)
        throws ACLException, Exception
    {        
        //TODO: Throw an exception if the user hadn't requested this role?
        revokeRole(acl, role, project);

        mailUserAboutRole(ROLE_REQUEST_DENIED_TEMPLATE,
                          "Requested role has not been granted", 
                          role, project);
    }

    /**
     * Grants to this user the specified role in the host.
     */
    public void grantHostRole(AccessControlList acl, Role role)
        throws ACLException, Exception
    {
        grantRole(acl, role, ProjectPeer.getHostProject());
    }

    /**
     * Grants to this user the specified role in the domain.
     */
    public void grantRole(AccessControlList acl, Role role, Domain domain)
        throws ACLException, Exception
    {
        grantRole(acl, role, domain.getSpecialProject());
    }

    /**
     * Grants to this user the specified role in the specified project.
     */
    public void grantRole(AccessControlList acl, Role role, Project project)
        throws ACLException, Exception
    {
        acl.getUser().assertRoleGrantPermission(project);

        boolean rebuildIssueTracking = role.affectsIssueTracking();
        IssueTrackingAccountDescriptor before = null;
        if (rebuildIssueTracking)
        {
            before = new IssueTrackingAccountDescriptor(project, this);
        }

        UserRoleProject mapping = new UserRoleProject();
        mapping.setUserId(getUserId());
        mapping.setRoleId(role.getRoleId());
        mapping.setProjectId(project.getProjectId());
        mapping.setApprovedBy(acl.getUser().getUserId());
        mapping.save();

        // TODO: Uncomment.
        // People in charge of a project should have their names
        // names in a special alias -- owner@@{project}.{domain}
        if (role.denotesOwner() && role.getType().equals(Role.PROJECT_TYPE)) 
        {
            //AnzuTask.setOwnerAlias(this, project, true);
        }

        if (rebuildIssueTracking)
        {
            IssueTrackingAccountDescriptor after = new
                IssueTrackingAccountDescriptor(project, this);
            before.syncTo(after, acl.getUser());        
        }
        AuditLog.logEvent(acl.getUser(), project, AUDIT_LOG_ON_ROLE_GRANT 
                          + getLoginName() + " <- " + role.getName());
                          
    }

    /**
     * Revokes from this user a role in the host.
     */
    public void revokeHostRole(AccessControlList acl, Role role)
        throws ACLException, Exception
    {
        revokeRole(acl, role, ProjectPeer.getHostProject());
    }

    /**
     * Revokes from this user a role in the given domain.
     */
    public void revokeRole(AccessControlList acl, Role role, Domain domain)
        throws ACLException, Exception
    {
        revokeRole(acl, role, domain.getSpecialProject());
    }

    /**
     * Revokes from this user a role in the specified project.
     */
    public void revokeRole(AccessControlList acl, Role role, Project project)
        throws ACLException, Exception
    {        
        acl.getUser().assertRoleGrantPermission(project);

        //Special case: The superuser cannot lose a role which gives
        //them ownership over the host.
        if (isSuperUser() && role.denotesOwner() 
            && role.getType().equals(Role.HOST_TYPE))
        {
            throw new Exception("Superuser cannot lose host ownership role.");
        }

        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.ROLE_ID, getUserId())
            .add(UserRoleProjectPeer.PROJECT_ID, getUserId());
        UserRoleProjectPeer.doDelete(c);

        // TODO: If they no longer have any ownership roles,
        // remove them from the member list.
        AuditLog.logEvent(acl.getUser(), project, AUDIT_LOG_ON_ROLE_GRANT 
                          + getLoginName() + " -> " + role.getName());
    }
}
@


1.1.2.1
log
@Classes ported to the Turbine Peer system. -dlr and leonardr
@
text
@a0 481
/* ================================================================
 * Copyright (c) 2001 CollabNet.  All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if
 * any, must include the following acknowlegement: "This product includes
 * software developed by CollabNet (http://www.collab.net/)."
 * Alternately, this acknowlegement may appear in the software itself, if
 * and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@@collab.net.
 * 
 * 5. Products derived from this software may not use the "Tigris" name
 * nor may "Tigris" appear in their names without prior written
 * permission of CollabNet.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL COLLABNET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals on behalf of CollabNet.
 */

package org.tigris.helm.om;

import java.util.*;

import org.apache.turbine.om.BaseObject;
import org.apache.turbine.om.peer.BasePeer;
import org.apache.turbine.util.db.Criteria;
import org.apache.turbine.util.ObjectUtils;
import org.apache.turbine.util.StringUtils;
import org.apache.turbine.util.ParameterParser;
import org.apache.turbine.util.Log;
import org.apache.turbine.util.db.pool.DBConnection;

import org.tigris.helm.DoesNotExist;
import org.tigris.helm.om.peer.*;
import org.tigris.helm.security.*;
import org.tigris.helm.tool.PeerTool;

/** 
 * User business object.
 *
 * @@author <a href="mailto:leonardr@@collab.net">Leonard Richardson</a>
 * @@author <a href="mailto:dlr@@collab.net">Daniel Rall</a>
 */
public class User extends BaseUser implements Comparable
{
    
    //
    // Accessor methods for a particular user.
    //
    
    public final String getID()
    {
        return getPrimaryKeyAsString();
    }
    
    public final String getDomainID()
    {
        return "" + getDomainId();
    }

    public int compareTo(Object o)
        throws ClassCastException
    {
        User u = (User)o;
        return getRealName().compareTo(u.getRealName());
    }

    public boolean equals(User u)
    {
        return (getID().equals(u.getID()));
    }

//     public void rebuildACL()
//         throws DoesNotExist
//     {
//         for (Iterator i = expand().iterator(); i.hasNext(); ) {
//             User u = (User)i.next();
//             AccessControlList.rebuildACL(dMgr, u.getID());
//         }
//     }

//     /**
//      * Returns a list of Users represending all the users
//      * this user represents. If called on a base user, 
//      * returns a list containing only itself.
//      */    
//     public List expand() 
//         throws DoesNotExist, DBException
//     {
//         List users = null;
// 	if (isBase()) {
// 	    users = new ArrayList();
// 	    users.add(this);
// 	}
//      else {
// 	    users = asGroup().expand();
// 	}
//         return users;
//     }

//     public UserGroup asGroup()
//     {
//         UserGroup g = null;
//         if (isGroup()) {
//                 g = new UserGroup(dMgr, this.rec);
//         }
//         return g;
//     }

//     /**
//      * The grant permission implies revoke as well. 
//      */
//     public void assertRoleGrantPermission (Project project)
//         throws ACLException, DBException
//     {
//         getACL().assertPermissionForProject
//             (project.requiredRoleGrantAction(), project.getID());
//     }
                                      
//     public boolean hasRoleGrantPermission (Project project)
//         throws ACLException, DBException
//     {
//         return getACL().hasPermissionForProject
//             (project.requiredRoleGrantAction(), project.getID());
//     }

//     public List getRequestedRolesInProject (String projectID)
//         throws DoesNotExist, DBException
//     {
//         ArrayList roles = new ArrayList ();
//         DataSet roleset = urpMgr.getRequestedRolesForUserProject(getUserID(),
//                                                                  projectID);
//         for (int i = 0; i < roleset.size (); i++)
//         {
//             Record r = rMgr.getRole(roleset.getRecord(i)
//                                     .getValue(UserRoleProjectManager.ROLE_ID)
//                                     .toString());
//             roles.add(new Role(dMgr, r));
//         }
//         return roles;
//     }

//     public List getRolesInProject (String projectID)
//         throws DoesNotExist, DBException
//     {
        
//         ArrayList roles = new ArrayList ();
//         DataSet roleset = urpMgr.getRolesForUserProject(getID(), projectID);
//         for (int i = 0; i < roleset.size (); i++)
//         {
//             Record r = rMgr.getRole(roleset.getRecord(i)
//                                     .getValue(UserRoleProjectManager.ROLE_ID)
//                                     .toString ());
//             roles.add(new Role(dMgr, r));
//         }
//         return roles;
//     }

//     public List getAvaliableRolesInProject (String projectID)
//         throws DoesNotExist, DBException
//     {
//         String rID = UserRoleProjectManager.ROLE_ID;
//         DataSet allRoles = rMgr.listRolesByType("project");
//         ArrayList avaliableRoles = new ArrayList();

//         Map approved = new HashMap();
//         DataSet approvedRoles = urpMgr.getRolesForUserProject(getUserID(),
//                                                               projectID);
//         for (int i = 0; i < approvedRoles.size(); i++)
//         {
//             approved.put(approvedRoles.getRecord(i).getValue(rID).toString(),
//                          Boolean.TRUE);
//         }

//         Map requested = new HashMap();
//         DataSet requestedRoles = urpMgr.getRequestedRolesForUserProject 
//             (getUserID(), projectID);
//         for (int i = 0; i < requestedRoles.size(); i++)
//         {
//             requested.put(requestedRoles.getRecord(i).getValue(rID).toString(),
//                           Boolean.TRUE);
//         }
        
//         for (int i = 0; i < allRoles.size(); i++)
//         {
//             String roleID = allRoles.getRecord(i).getValue
//                 (RoleManager.ROLE_ID).toString();
//             Role role = new Role(dMgr, roleID);
//             if (!requested.containsKey(roleID)
//                 && !approved.containsKey(roleID) 
//                 && role.isRequestable())
//             {
//                 avaliableRoles.add(role);
//             }
//         }
//         return avaliableRoles;
//     }

//     public List getProjectsForUserGroups()
//         throws DoesNotExist, DBException
//     {        
//         // Get groups the user is a member of 
//         DataSet userGroups = usrGrpMgr.getCompositesForBase(getUserID());

//         // Create list of userID's including IDs of groups
//         ArrayList effectiveUserIDs = new ArrayList();
//         effectiveUserIDs.add(getUserID());        
//         if (userGroups != null)
//         {
// 	    for (int i = 0; i < userGroups.size(); i++)
// 	    {
//                 effectiveUserIDs.add(userGroups.getRecord(i)
//                                      .getValue(usrGrpMgr.USER_GROUP_ID));
//             }
// 	}

//         // Get dataset of projects for these users
//         DataSet projects = urpMgr.getProjectsForUsers(effectiveUserIDs);

//         ArrayList projectsForUser = new ArrayList();
// 	String projectID;

//         for (int i = 0; i < projects.size(); i++)
//         {
//             projectID = projects.getRecord(i)
//                 .getValue(UserRoleProjectManager.PROJECT_ID).toString();
//             projectsForUser.add(new Project(dMgr, projectID));
//         }

// 	return projectsForUser;
//     }


    //     public List getProjectsForUser ()
    //         throws Exception
//     {        
//         ArrayList projects = new ArrayList ();
//         DataSet projectset = urpMgr.getProjectsForUser(getUserID());
        
//         for (int i = 0; i < projectset.size (); i++)
//         {
//             Record r = projectset.getRecord (i);
//             projects.add(new Project(dMgr, r));
//         }
//         return projects;
//     }

    //
    // Mutator methods
    //

    /**
     * Constructor for a new user. Adds the user, adding them to the 
     * default user group.
     */
    public static User add
        (AccessControlList acl, String domainID, String realName,
         String loginID, String password, String email)
        throws Exception
    {
        return add(acl, domainID, realName, loginID, password, email, null);
    }

    /**
     * Adds a new user. Also adds the user to the default user group.
     */
    public static User add 
        (AccessControlList acl, String domainID, String realName,
         String loginName, String password, String email, String organization)
        throws Exception
    {
        //try {
        //MailingAliasSpec alias;
        //Domain domain = Domain.getInstance(domainID);
        //alias = new MailingAliasSpec(domain.getName(), "www", userName);
        //alias.setDestination(email);
        //alias.create();
        //} catch (Exception e) {
        //  log.exception(e);
        //  if (debug) log.error("unable to setup email: " + e.getMessage());
        //throw new UpdateException("Unable to setup e-mail alias");
        //}
        
        User user = new User();
        try {
            user.setDomainId(Integer.parseInt(domainID));
            user.setRealName(realName);
            user.setLoginName(loginName);
            user.setPassword(password); //FIXME
            user.setEmail(email);
            user.setOrganization(organization);
            user.setType(UserType.REGULAR);
            user.save();
            // Add the user to the appropriate user group.
            //UserGroup.addUserToDomainUserGroup(dMgr, domainID, this);
        
        } catch (Exception e) {
            //try {
            //alias.delete();
            //} catch (HandlerException he) {
            //log.exception(he);
            //log.error("Error attempting to delete alias for " + userName +
            //" as part of rollback: " + he.getMessage());
            //}
            throw new Exception("Unable to finish creating User: " +
                                e.getMessage());
        }
        return user;
    }

    /**
     * Determines whether the user is the application's guest user.  Useful in
     * WebMacro template code.
     *
     * @@return Whether the guest user.
     */
    public boolean isGuest()
        throws Exception
    {
        return getID().equals(UserPeer.getGuestUser().getID());
    }

    /**
     * Determines whether the password ticket is valid.
     *
     * @@param ticket The ticket to compare.
     */
    public boolean isValidPasswordTicket (String ticket)
        throws Exception
    {
        // TODO: Fail on database NULL.
        return (ticket != null && 
                ticket.equals(getPasswordticket()));
    }

    public void update(AccessControlList acl, 
                       String loginID, String email, 
                       String realName, String organization, 
                       String password, String passwordConfirm)
        throws ACLException, Exception
    {
        if (!password.equals(passwordConfirm))
        {
            throw new Exception("Passwords do not match.");
        }
        assertEditPermission(acl);
        
//          if (!email.equals(getEmail())) {
//              try {
//                  Domain domain = new Domain(dMgr, getDomainID());
//                  MailingAliasSpec alias =
//                      new MailingAliasSpec(domain.getName(), "www", loginID);
//                  alias.setDestination(email);
//                  alias.update();
//              } catch (Exception e) { // Domain constructor throws this ... bleah
//                  log.error("unable to update email address for " + loginID +
//                            ": " + e.getMessage());
//                  log.exception(e);
//                  // TODO : should we throw an exception?  this method should
//                  // really only throw UpdateException & ACLException ...
//                  // UpdateException would be the right thing to throw.
//              }
//          }

        //User - Edit - Self is not sufficient to change organization.
        if (!acl.hasPermissionForDomain("User - Edit", getDomain()))
        {
            organization = getOrganization();
        }
         
        if (realName != null) setRealName(realName);
        if (email != null) setEmail(email);
        if (password != null) setPassword(password); //FIXME
        if (organization != null) setOrganization(organization);
        save();         
    }
    
     /**
      * Updates the user's password.
      *
      * @@param passwd        The new password to use.
      * @@param passwdConfirm Confirmation of the new password.
      *
      */
     public void changePassword 
         (AccessControlList acl, String password, String passwordConfirm)
         throws ACLException, Exception
     {
         update(acl, null, null, null, null, password, passwordConfirm);
     }

    public void delete(AccessControlList acl)
        throws ACLException, Exception
    {
        acl.assertPermissionForDomain("User - Delete", getDomain());

        User deletingUser = acl.getUser();
//         //Remove the user from all composite users.
//         for (Iterator i = getGroups().iterator(); i.hasNext();)
//         {
//             UserGroup u = (UserGroup)i.next();
//             removeFromGroup(acl, u);
//         }               

//          //Remove the user from all Issuezilla databases they're in.
//          AccessControlList userACL = AccessControlList.getInstanceForUser(getID());
//          List projects = pMgr.getProjectsForDomain(getDomainID());

//          //Revoke all the user's roles.
//          revokeRoles(new Criteria());

//          // Having deleted the user from individual projects, delete
//          // the user from all projects in domain.  Mostly affects
//          // Issuezilla.
//          TigrisUpdate.deleteUser(deletingUser, getDomain(), this);

         //Remove the user proper.
         UserPeer.doDelete(new Criteria().add(UserPeer.USER_ID, getID()));

//          // remove the alias
//          try {
//              Domain domain = getDomain();
//              MailingAliasSpec alias =
//                  new MailingAliasSpec(domain.getName(), "www", getLoginID());
//              alias.delete();
//          } catch (Exception e) {
//              log.error("unable to delete email address for " + getName() +
//                        ": " + e.getMessage());
//              log.exception(e);
//          }              
     }

    //
    // Role and permission management
    //
    
    private void assertEditPermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (acl.getUserID().equals(getID())) {
            acl.assertPermissionForDomain("User - Edit - Self", getDomain());
        }
        else {
            acl.assertPermissionForDomain("User - Edit", getDomain());
        }
    }

    public Domain getDomain()
        throws Exception
    {
        return DomainPeer.retrieveById(getDomainID());
    }
}
   
@


1.1.2.2
log
@Uncommented the now compilable rebuildACL() method.
@
text
@d100 8
a107 8
    public void rebuildACL()
        throws DoesNotExist
    {
        for (Iterator i = expand().iterator(); i.hasNext(); ) {
            User u = (User)i.next();
            AccessControlList.rebuildACL(dMgr, u.getID());
        }
    }
@


1.1.2.3
log
@* Implemented the UserType interface.
* Added associated boolean check methods to interogate type.
* Updated rebuildACL() implementation.
* Got most of expand() compiling.
@
text
@d71 1
a71 1
public class User extends BaseUser implements UserType, Comparable
d73 1
d101 1
a101 1
        throws DoesNotExist, Exception
d105 1
a105 1
            AccessControlList.rebuildACL(this);
d109 18
a126 17
    /**
     * Returns a list of Users represending all the users this user represents.
     * If called on a base user, returns a list containing only itself.
     */    
    public List expand()
        throws DoesNotExist, Exception
    {
        List users = null;
	if (isBase()) {
	    users = new ArrayList(1);
	    users.add(this);
	}
//         else {
//             users = asGroup().expand();
//         }
        return users;
    }
d132 1
a132 1
//             g = new UserGroup();
d141 1
a141 1
//         throws ACLException, Exception
d148 1
a148 1
//         throws ACLException, Exception
d319 1
a319 1
            user.setType(REGULAR_TYPE);
a479 21

    public boolean isDomain()
    {
        return getType().equals(DOMAIN_TYPE);
    }

    public boolean isHost()
    {
        return getType().equals(HOST_TYPE);
    }

    public boolean isBase()
    {
        String type = getType();
        return (type.equals(REGULAR_TYPE) || type.equals(NOBODY_TYPE));
    }

    public boolean isGroup()
    {
	return !isBase();
    }
d481 1
@


1.1.2.4
log
@Corrected bug I introduced in my last commit where "this" was passed
every time instead of users in list if user is user group.
@
text
@d103 2
a104 1
            AccessControlList.rebuildACL((User)i.next());
@


1.1.2.5
log
@Ported getProjectsForUser() method.
@
text
@d115 4
a118 4
    if (isBase()) {
        users = new ArrayList(1);
        users.add(this);
    }
d234 2
a235 2
//         for (int i = 0; i < userGroups.size(); i++)
//         {
d239 1
a239 1
//     }
d245 1
a245 1
//     String projectID;
d254 1
a254 1
//     return projectsForUser;
d257 14
a270 17
    /**
     * Returns all projects associated with this user.
     */
    public List getProjectsForUser()
        throws Exception
    {        
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getID());
        List urps = UserRoleProjectPeer.doSelect(c);
        List projects = new ArrayList(urps.size());
        UserRoleProject urp;
        for (Iterator i = urps.iterator(); i.hasNext(); ) {
            urp = (UserRoleProject)i.next();
            projects.add(ProjectPeer.retrieveByPK(urp.getProjectId()));
        }
        return projects;
    }
d496 1
a496 1
        return !isBase();
@


1.1.2.6
log
@* Prep'd delete() for port.
* Changed interface of add() methods to take a Domain object instead
  of a domainID.
@
text
@d283 3
a285 3
    public static User add(AccessControlList acl, Domain domain,
                           String realName, String loginID, String password,
                           String email)
d288 1
a288 1
        return add(acl, domain, realName, loginID, password, email, null);
d294 3
a296 3
    public static User add(AccessControlList acl, Domain domain,
                           String realName, String loginName, String password,
                           String email, String organization)
d301 1
d313 1
a313 1
            user.setDomainId(domain.getDomainId());
d324 1
a324 2
        }
        catch (Exception e) {
a418 7
    /**
     * Deletes the corresponding user record from the database.
     *
     * @@param acl The ACL of the user performing the delete.
     *
     * @@exception Exception Likely a database error.
     */
d432 2
a433 2
          //Remove the user from all Issuezilla databases they're in.
          AccessControlList userACL = AccessControlList.getACL(this);
d437 1
a437 1
//          revokeRoles();
a457 1
        UserPeer.doDelete(this);
@


1.1.2.7
log
@Moved factory methods back into User.  By decree of Leonard, Daniel,
and John, factory methods shalt dwell in thy business objects!
@
text
@d60 1
a60 1
import org.tigris.helm.*;
a73 83
    // Ways of retrieving User objects.
    //

    /**
     * Returns the user with the specified ID.
     */
    public static User getInstance(String userID)
        throws Exception
    {
        return UserPeer.retrieveByPK(Integer.parseInt(userID));
    }

    /**
     * Returns the user for a specified domain and login name.
     */
    public static User getInstanceByLoginName(Domain domain, String name)
        throws DoesNotExist, Exception
    {
        Criteria c = new Criteria()
            .add(UserPeer.LOGIN_NAME, name);
        checkThisAndHostDomain(c, domain);
        return (User)PeerTool.getFirstBO(UserPeer.doSelect(c),
                                         "User with login name of " + name,
                                         domain);
    }

    /**
     * Returns the user for a specified domain and real name.
     */
    public static User getInstanceByRealName(Domain domain, String name)
        throws DoesNotExist, Exception
    {
        Criteria c = new Criteria()
            .add(UserPeer.REAL_NAME, name);
        checkThisAndHostDomain(c, domain);
        return (User)PeerTool.getFirstBO(UserPeer.doSelect(c),
                                         "User named " + name, domain);
    }

    /**
     * Returns the user for a specified domain and email address.
     */
    public static User getInstanceByEmail(Domain domain, String email)
        throws DoesNotExist, Exception
    {
        Criteria c = new Criteria()
            .add(UserPeer.EMAIL, email);
        checkThisAndHostDomain(c, domain);
        return (User)PeerTool.getFirstBO(UserPeer.doSelect(c),
                                         "User with email " + email, domain);
    }
    
    private static Criteria checkThisAndHostDomain(Criteria c, Domain domain)
        throws Exception
    {
        String[] domainIDs = { domain.getID(),
                               DomainPeer.getHostDomain().getID() };
        c.addIn(UserPeer.DOMAIN_ID, domainIDs);
        return c;
    }

    /**
     * Throws an exception if the specified information corresponds to an
     * existing user.
     *  
     * @@param domain    The domain to check.
     * @@param loginName The login name of the user to search for.
     * @@param
     */
    public static void assertNonexistance(Domain domain, String loginName)
        throws AlreadyExists, Exception
    {
        Criteria c = new Criteria()
            .add(UserPeer.LOGIN_NAME, loginName);
        checkThisAndHostDomain(c, domain);
        List u = UserPeer.doSelect(c);
        if (u.isEmpty()) {
            throw new AlreadyExists("User with loginName of " + loginName,
                                    "domain named " + domain);
        }
    }

    //
d84 1
a84 1
        return String.valueOf(getDomainId());
@


1.1.2.8
log
@More porting for projects and user groups.
@
text
@d363 2
a364 1
     * Adds a new base user.
d366 4
a369 4
    public static User add
        (AccessControlList acl, Domain domain, String realName, 
         String loginName, String type)
        throws ACLException, Exception
d371 1
a371 1
        return add(acl, domain, realName, loginName, null, null, null, type);
d375 1
a375 1
     * Adds a new base user.
d377 4
a380 4
    public static User add
        (AccessControlList acl, Domain domain, String realName,
         String loginName, String password, String email)
        throws ACLException, Exception
d382 11
a392 39
        return add(acl, domain, realName, loginName, password, email, null, 
                   REGULAR_TYPE);
    }

    /**
     * Adds a new base user.
     */
    public static User add 
        (AccessControlList acl, Domain domain, String realName,
         String loginName, String password, String email, String organization)
        throws ACLException, Exception
    {
        return add(acl, domain, email, loginName, password, email,
                   organization, REGULAR_TYPE);
    }

    /**
     * Adds a new user of the specified type. 
     */
    public static User add 
        (AccessControlList acl, Domain domain, String realName,
         String loginName, String password, String email, String organization,
         String type)
        throws ACLException, Exception
    {
        if (type != REGULAR_TYPE)
        {
            //try {
            //MailingAliasSpec alias;
            //alias = new MailingAliasSpec(domain.getName(), "www", userName);
            //alias.setDestination(email);
            //alias.create();
            //} catch (Exception e) {
            //  log.exception(e);
            //  if (debug) log.error("unable to setup email: " + e.getMessage());
            //throw new UpdateException("Unable to setup e-mail alias");
            //}
        }

d401 1
a401 2
            user.setType(type);
            user.assertAddPermission(acl);
d403 3
a405 3

            //Add the user to the appropriate user group.
            user.addToDomainGroup();
d408 9
a416 12
            if (type == REGULAR_TYPE)
            {
                //try {
                //alias.delete();
                //} catch (HandlerException he) {
                //log.exception(he);
                //log.error("Error attempting to delete alias for " + userName +
                //" as part of rollback: " + he.getMessage());
                //}
                throw new Exception("Unable to finish creating User: " +
                                    e.getMessage());
            }
a420 11
    public void addToDomainGroup()
        throws Exception
    {
        AccessControlList acl = AccessControlList.getSuperUserACL();
        try {
            UserPeer.getDomainUser(getDomain()).addUser(acl, this);        
        } catch (ACLException e) {
            throw new Exception("Superuser is lacking permission to add user to group.");
        }
    }

d554 1
a554 12

    private void assertAddPermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (isBase())
        {
            acl.assertPermissionForDomain("User - Add", getDomain());
        } else {
            acl.assertPermissionForDomain("UserGroup - Add", getDomain());
        }
    }

a563 11
    }

    public UserGroup asGroup()
        throws Exception
    {
        if (isBase())
        {
            throw new Exception
                ("Attempt to transform non-group user to UserGroup.");
        } 
        return UserPeer.getGroupInstance(getID());
@


1.1.2.9
log
@Ported the ACL construction functionality.
@
text
@a189 20
    public List effectiveUserIDs()
        throws Exception
    {
        String myID = getID();

        Criteria myGroupMappingCrit = new Criteria()
            .add(UserUsergroupPeer.USER_ID, myID);
        List myGroupMappings = UserUsergroupPeer.doSelect(myGroupMappingCrit);

        List myIDs = new ArrayList();
        myIDs.add(myID);

        for (Iterator i = myGroupMappings.iterator(); i.hasNext();)
        {
            UserUsergroup mapping = (UserUsergroup)i.next();
            myIDs.add(mapping.getUserGroupID());
        }
        return myIDs;
    }

@


1.1.2.10
log
@More ACL porting.
@
text
@d193 6
d200 3
a202 2
        List users = expand();
        for (Iterator i = users.iterator(); i.hasNext();)
d204 2
a205 2
            User u = (User)i.next();
            myIDs.add(u.getID());
@


1.1.2.11
log
@Ported another snippet.
@
text
@d215 3
a217 3
        else {
            users = asGroup().expand();
        }
d613 2
a614 1
        if (isBase()) {
d616 1
a616 2
        }
        else {
@


1.1.2.12
log
@Use of memory comparisons is unsafe when taking String object
parameters.  What we want here is a strcmp().
@
text
@d419 2
a420 1
        if (type.equals(REGULAR_TYPE)) {
d426 1
a426 2
            //}
            //catch (Exception e) {
d449 2
a450 1
            if (type.equals(REGULAR_TYPE)) {
d453 1
a453 2
                //}
                //catch (HandlerException he) {
d471 1
a471 2
        }
        catch (ACLException e) {
@


1.1.2.13
log
@Super user should never lack the permission to do something.  Throw an
Error instead of an Exception.
@
text
@d473 1
a473 2
            throw new Error
                ("Super user lacks permission to add user to group.");
@


1.1.2.14
log
@Moved User factory methods back into UserPeer.  Ping pong.
@
text
@d73 62
d148 1
a148 1
        UserPeer.checkThisAndHostDomain(c, domain);
@


1.1.2.15
log
@Take advantage of the fact that we know the list size ahead of time,
and pre-allocate accordingly.
@
text
@d131 1
d133 1
a133 3
        List myIDs = new ArrayList(users.size());
        User u;
        for (Iterator i = users.iterator(); i.hasNext(); )
d135 1
a135 1
            u = (User)i.next();
@


1.1.2.16
log
@Corrected indentation.
@
text
@d150 4
a153 4
        if (isBase()) {
            users = new ArrayList(1);
            users.add(this);
        }
@


1.1.2.17
log
@added getACL method
@
text
@a159 6
    public AccessControlList getACL()
        throws Exception
    {
        return AccessControlList.getACL(this);
    }

@


1.1.2.18
log
@Changed getPrimaryKeyAsString() to (String)getPrimaryKey().
@
text
@d100 1
a100 1
        return (String)getPrimaryKey();
@


1.1.2.19
log
@Big patch to make access control work.
@
text
@a114 10
    public boolean equals(Object o)
    {
        if (o instanceof User)
        {
            return (equals((User)o));
        } else {
            return false;
        }
    }

@


1.1.2.20
log
@Added a couple necessary methods to User.
@
text
@a63 1
import org.tigris.helm.tool.Nonce;
a624 20
    }

    /**
     * Creates and saves a new password ticket.
     */
    public String newPasswordTicket ()
    //throws Exception
    {
        String ticket = Nonce.buildNonce();
        setPasswordTicket(ticket);
        return ticket;
    }
    /**
     * Removes a used password ticket.
     */
    public final void clearPasswordTicket ()
    //throws Exception
    {
        // NOTE: This looks fishy...
        setPasswordTicket("NULL");
@


1.1.2.21
log
@Cleanup on newly added ticket methods.
@
text
@d632 1
d642 1
d644 1
a644 2
        // NOTE: This implementation looks fishy...I'm worried the string
        // "NULL" will be the value used, rather than SQL NULL.
@


1.1.2.22
log
@More fixes for ACL and ACLDump.
@
text
@d142 4
a145 5
        Criteria c = new Criteria().add(UserUsergroupPeer.USER_ID,getID());
        List mappings = UserUsergroupPeer.doSelect(c);
        List myIDs = new ArrayList(mappings.size()+1);
        myIDs.add(getID());
        for (Iterator i = mappings.iterator(); i.hasNext();)
d147 2
a148 2
            UserUsergroup g = (UserUsergroup)i.next();
            myIDs.add(g.getUserGroupID());
@


1.1.2.23
log
@Added version tag.
@
text
@a70 1
 * @@version $Id: $
@


1.1.2.24
log
@Correcting password ticket member naming.
@
text
@d71 1
a71 1
 * @@version $Id: User.java,v 1.1.2.23 2001/02/02 17:38:13 dlr Exp $
d458 1
a458 1
                ticket.equals(getPasswordTicket()));
@


1.1.2.25
log
@Clarified TODO.
@
text
@d71 1
a71 1
 * @@version $Id: User.java,v 1.1.2.24 2001/02/02 18:13:30 dlr Exp $
d456 1
a456 1
        // TODO: Assure failure on database NULL.
@


1.1.2.26
log
@Ported issueTrackingAccountType method.
@
text
@d71 1
a71 1
 * @@version $Id: User.java,v 1.1.2.25 2001/02/02 18:18:00 dlr Exp $
d133 1
a133 1
        throws Exception
d160 1
a160 1
        throws Exception
a568 23

    /**
     * Return the type of issue tracking account this user has in the
     * given project. Used by IssueTrackingAccountMap.
     */
    public String issueTrackingAccountType(Project project)
        throws Exception
    {
	AccessControlList acl = getACL();
	String type="";
	if (acl.hasPermissionForProject
            ("Project Issue Tracking - Configure", project))
        {
            type = "admin";
        } else if (acl.hasPermissionForProject
                   ("Project Issue Tracking - Change", project)) {
            type = "developer";
        } else if (acl.hasPermissionForProject
                   ("Project Issue Tracking - Submit", project)) {
            type = "observer";
        }
	return type;
    }
@


1.1.2.27
log
@Ported a bunch more methods.
@
text
@a65 2
import org.tigris.helm.tool.task.IssueTrackingAccountDescriptor;

d71 1
a71 1
 * @@version $Id: User.java,v 1.1.2.26 2001/02/05 15:40:56 leonardr Exp $
a103 27

    public Domain getDomain()
        throws Exception
    {
        return DomainPeer.retrieveById(getDomainID());
    }

    public boolean isDomain()
    {
        return getType().equals(DOMAIN_TYPE);
    }

    public boolean isHost()
    {
        return getType().equals(HOST_TYPE);
    }

    public boolean isBase()
    {
        String type = getType();
        return (type.equals(REGULAR_TYPE) || type.equals(NOBODY_TYPE));
    }

    public boolean isGroup()
    {
        return !isBase();
    }
a131 14
    /**
     * Determines whether the user is the application's guest user.  Useful in
     * WebMacro template code.
     *
     * @@return Whether the guest user.
     */
    public boolean isGuest()
        throws Exception
    {
        return getID().equals(UserPeer.getGuestUser().getID());
    }



a155 18
     * Return a list of all groups to which this user belongs, including
     * the special domain group.
     */
    public List getGroups()
        throws Exception
    {
        Criteria c = new Criteria().add(UserUsergroupPeer.USER_ID,getID());
        List mappings = UserUsergroupPeer.doSelect(c);
        List groups = new ArrayList(mappings.size());
        for (Iterator i = mappings.iterator(); i.hasNext();)
        {
            UserUsergroup g = (UserUsergroup)i.next();
            groups.add(UserPeer.getInstance(String.valueOf(g.getUserId())));
        }
        return groups;
    }

    /**
d179 25
a203 10
    public UserGroup asGroup()
        throws Exception
    {
        if (isBase())
        {
            throw new Exception
                ("Attempt to transform non-group user to UserGroup.");
        } 
        return UserPeer.getGroupInstance(getID());
    }
d205 15
d221 15
a235 9
    /**
     * Creates and saves a new password ticket.
     */
    public String newPasswordTicket ()
    {
        String ticket = Nonce.buildNonce();
        setPasswordTicket(ticket);
        return ticket;
    }
d237 6
a242 9
    /**
     * Removes a used password ticket.
     */
    public final void clearPasswordTicket ()
    {
        // NOTE: This implementation looks fishy...I'm worried the string
        // "NULL" will be the value used, rather than SQL NULL.
        setPasswordTicket("NULL");
    }
d244 8
a251 12
    /**
     * Determines whether the password ticket is valid.
     *
     * @@param ticket The ticket to compare.
     */
    public boolean isValidPasswordTicket (String ticket)
        throws Exception
    {
        // TODO: Assure failure on database NULL.
        return (ticket != null && 
                ticket.equals(getPasswordTicket()));
    }
d253 23
d423 38
d527 1
a527 2
        Domain domain = getDomain();
        acl.assertPermissionForDomain("User - Delete", domain);
d530 25
a554 18
        //Remove the user from all composite users.
        for (Iterator i = getGroups().iterator(); i.hasNext();)
        {
            UserGroup u = (UserGroup)i.next();
            removeFromGroup(acl, u);
        }               

        //Revoke all the user's roles, requested or granted.
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId());
        UserRoleProjectPeer.doDelete(c);

        // Having deleted the user from individual projects, delete
        // the user from the domain.  Mostly affects Issuezilla.
        HelmTask.deleteUser(deletingUser, domain, this);

//          // remove the Anzu alias
//          try {            
d563 1
a563 4

        //Remove the user proper.
        UserPeer.doDelete(new Criteria().add(UserPeer.USER_ID, getID()));

a566 29
    // Group management
    //

    public void addToDomainGroup()
        throws Exception
    {
        AccessControlList acl = AccessControlList.getSuperUserACL();
        try {
            UserPeer.getDomainUser(getDomain()).addUser(acl, this);        
        }
        catch (ACLException e) {
            throw new Error
                ("Super user lacks permission to add user to group.");
        }
    }

    public void addToGroup(AccessControlList acl, UserGroup g)
        throws ACLException, Exception
    {
        g.addUser(acl, this);
    }

    public void removeFromGroup(AccessControlList acl, UserGroup g)
        throws ACLException, Exception
    {
        g.removeUser(acl, this);
    }

    //
d615 2
a616 7
    /**
     * Throws an ACLException if this user cannot grant roles in the
     * given project.  Note that the grant permission implies revoke
     * as well.  
     */
    public void assertRoleGrantPermission (Project project)
        throws ACLException, Exception
d618 6
a623 2
        getACL().assertPermissionForProject
            (project.requiredRoleGrantAction(), project);
d626 1
a626 6
    /**
     * Returns true if this user can grant roles in the given
     * project.  Note that the grant permission implies revoke as
     * well.  
     */
    public boolean hasRoleGrantPermission (Project project)
d629 1
a629 2
        return getACL().hasPermissionForProject
            (project.requiredRoleGrantAction(), project);
d632 1
a632 5
    /**
     * Returns all the roles which a user has been granted in a project.
     */
    public List getRolesInProject (Project project)
        throws Exception
d634 1
a634 1
        return getRolesInProject(project, true);
d637 1
a637 5
    /**
     * Returns all the roles which a user has requested in a project.
     */
    public List getRequestedRolesInProject (Project project)
        throws Exception
d639 1
a639 1
        return getRolesInProject(project, false);
d642 1
a642 6
    /**
     * Does the heavy lifting for getRolesInProject and
     * getRequestedRolesInProject.
     */
    private List getRolesInProject (Project project, boolean approved)
        throws Exception
d644 2
a645 14
        String matchType = approved?Criteria.NOT_EQUAL:Criteria.EQUAL;
        List roles = new ArrayList ();
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.PROJECT_ID, project.getProjectId())
            .add(UserRoleProjectPeer.APPROVED_BY, 
                 UserPeer.getNobodyUser().getUserId(), matchType);
        List mappings = UserRoleProjectPeer.doSelect(c);
        for (Iterator i = mappings.iterator(); i.hasNext();)
        {
            UserRoleProject mapping = (UserRoleProject)i.next();
            roles.add(RolePeer.getInstance(String.valueOf(mapping.getRoleId())));
        }
        return roles;
d648 1
a648 49
//    /**
//     * Returns all the requestable roles of the appropriate type
//     * which the user does not currently posess.
//     */
//     public List getAvaliableRolesInProject (String projectID)
//         throws DoesNotExist, DBException
//     {
//         String rID = UserRoleProjectManager.ROLE_ID;
//         DataSet allRoles = rMgr.listRolesByType("project");
//         ArrayList avaliableRoles = new ArrayList();

//         Map approved = new HashMap();
//         DataSet approvedRoles = urpMgr.getRolesForUserProject(getUserID(),
//                                                               projectID);
//         for (int i = 0; i < approvedRoles.size(); i++)
//         {
//             approved.put(approvedRoles.getRecord(i).getValue(rID).toString(),
//                          Boolean.TRUE);
//         }

//         Map requested = new HashMap();
//         DataSet requestedRoles = urpMgr.getRequestedRolesForUserProject 
//             (getUserID(), projectID);
//         for (int i = 0; i < requestedRoles.size(); i++)
//         {
//             requested.put(requestedRoles.getRecord(i).getValue(rID).toString(),
//                           Boolean.TRUE);
//         }
        
//         for (int i = 0; i < allRoles.size(); i++)
//         {
//             String roleID = allRoles.getRecord(i).getValue
//                 (RoleManager.ROLE_ID).toString();
//             Role role = new Role(dMgr, roleID);
//             if (!requested.containsKey(roleID)
//                 && !approved.containsKey(roleID) 
//                 && role.isRequestable())
//             {
//                 avaliableRoles.add(role);
//             }
//         }
//         return avaliableRoles;
//     }

    /**
     * Requests for this user the specified role in the specified project.
     */
    public void requestRole(Role role, Project project)
        throws ACLException, Exception
d650 1
a650 8
        AccessControlList acl = getACL();
        acl.assertPermissionForProject("Project Role - Request", project);
        UserRoleProject mapping = new UserRoleProject();
        mapping.setUserId(getUserId());
        mapping.setRoleId(role.getRoleId());
        mapping.setProjectId(project.getProjectId());
        mapping.setApprovedBy(UserPeer.getNobodyUser().getUserId());
        mapping.save();
d654 1
a654 1
     * Grants to this user the specified role in the specified project.
d656 1
a656 2
    public void grantRole(AccessControlList acl, Role role, Project project)
        throws ACLException, Exception
d658 3
a660 22
        acl.getUser().assertRoleGrantPermission(project);

        boolean rebuildIssueTracking = role.affectsIssueTracking();
        IssueTrackingAccountDescriptor before = null;
        if (rebuildIssueTracking)
        {
            before = new IssueTrackingAccountDescriptor(project, this);
        }

        UserRoleProject mapping = new UserRoleProject();
        mapping.setUserId(getUserId());
        mapping.setRoleId(role.getRoleId());
        mapping.setProjectId(project.getProjectId());
        mapping.setApprovedBy(acl.getUser().getUserId());
        mapping.save();

        if (rebuildIssueTracking)
        {
            IssueTrackingAccountDescriptor after = new
                IssueTrackingAccountDescriptor(project, this);
            before.syncTo(after, acl.getUser());        
        }
a661 1
    
d663 1
a663 1
     * Revokes from this user the specified role in the specified project.
d665 1
a665 2
    public void revokeRole(AccessControlList acl, Role role, Project project)
        throws ACLException, Exception
d667 3
a669 7
        acl.getUser().assertRoleGrantPermission(project);
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.ROLE_ID, getUserId())
            .add(UserRoleProjectPeer.PROJECT_ID, getUserId());
        UserRoleProjectPeer.doDelete(c);
        
@


1.1.2.28
log
@Ported (added, really) validator classes.
@
text
@a59 2
import gnu.regexp.*;

d73 1
a73 1
 * @@version $Id: User.java,v 1.1.2.27 2001/02/05 20:24:02 leonardr Exp $
a76 27

    /**
     * The regular expression used to validate login names.
     */
    private static RE loginNameRE;

    /**
     * The regular expression used to validate real names.
     */
    private static RE realNameRE;

    static
    {
        try
        {
            // HELP: Are these things thread safe?
            loginNameRE = new RE("^[\\w]{1,16}$");
            loginNameRE = new RE("^[\\w' \\-\\.\\,\\(\\)]+$");
        }
        catch (REException e)
        {
            throw new Error("Could not initialize regular expressions for user.");
        }

        //TODO: Cache guest user (and superuser?)
    }

a95 22
    }

    /**
     * Checks whether a login name is valid.
     *
     * @@param loginName The login name to check.
     * @@return          Whether the name is valid.
     */
    public static boolean isValidLoginName (String loginName)
    {
        return (loginName != null && loginNameRE.isMatch(loginName));
    }

    /**
     * Checks whether a real name is valid.
     *
     * @@param realName The real name to check.
     * @@return         Whether the name is valid.
     */
    public static boolean isValidRealName (String realName)
    {
        return (realName != null && realNameRE.isMatch(realName));
@


1.1.2.29
log
@Let's see a full stack trace if there is an error adding the user.
@
text
@a57 1
import org.apache.turbine.util.TurbineException;
d75 1
a75 1
 * @@version $Id: User.java,v 1.1.2.28 2001/02/06 17:53:58 leonardr Exp $
d476 2
a477 1
                throw new TurbineException("Unable to finish creating User", e);
@


1.1.2.30
log
@Fixed RE misnaming and changed thrown exception.
@
text
@d76 1
a76 1
 * @@version $Id: User.java,v 1.1.2.29 2001/02/06 18:14:11 dlr Exp $
d97 1
a97 1
            realNameRE = new RE("^[\\w' \\-\\.\\,\\(\\)]+$");
d477 1
a477 1
                throw new TurbineException("Unable to finish creating User: " + e.getMessage(), e);
@


1.1.2.31
log
@Fixed exception throw.
@
text
@d76 1
a76 1
 * @@version $Id: User.java,v 1.1.2.30 2001/02/06 18:55:44 leonardr Exp $
d477 1
a477 1
                 throw new TurbineException("Unable to finish creating User: ", e);
@


1.1.2.32
log
@No semi-colon needed.
@
text
@d76 1
a76 1
 * @@version $Id: User.java,v 1.1.2.31 2001/02/06 19:07:58 leonardr Exp $
d477 1
a477 1
                throw new TurbineException("Unable to finish creating User", e);
@


1.1.2.33
log
@Added methods for UserEdit.
@
text
@d76 1
a76 1
 * @@version $Id: User.java,v 1.1.2.32 2001/02/06 19:09:04 dlr Exp $
a389 2
    

d483 2
a484 1
    public void update(AccessControlList acl, String email, 
d499 1
a499 1
//                      new MailingAliasSpec(domain.getName(), "www", loginName);
d503 1
a503 1
//                  log.error("unable to update email address for " + loginName +
d536 1
a536 1
         update(acl, null, null, null, password, passwordConfirm);
d641 1
a641 1
    public void assertAddPermission(AccessControlList acl)
d652 1
a652 25
    public void assertDeletePermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (isBase()) {
            acl.assertPermissionForDomain("User - Delete", getDomain());
        }
        else {
            acl.assertPermissionForDomain("UserGroup - Delete", getDomain());
        }
    }

    public boolean hasDeletePermission(AccessControlList acl)
        throws Exception
    {
        boolean ok = false;
        if (isBase()) {
            ok = acl.hasPermissionForDomain("User - Delete", getDomain());
        }
        else {
            ok = acl.hasPermissionForDomain("UserGroup - Delete", getDomain());
        }
        return ok;
    }

    public void assertEditPermission(AccessControlList acl)
a662 11
    public void assertViewPermission(AccessControlList acl)
        throws ACLException, Exception
    {
        if (acl.getUserID().equals(getID())) {
            acl.assertPermissionForDomain("User - View - Self", getDomain());
        }
        else {
            acl.assertPermissionForDomain("User - View", getDomain());
        }
    }

a788 18
     * Grants to this user the specified role in the host.
     */
    public void grantHostRole(AccessControlList acl, Role role)
        throws ACLException, Exception
    {
        grantRole(acl, role, ProjectPeer.getHostProject());
    }

    /**
     * Grants to this user the specified role in the domain.
     */
    public void grantRole(AccessControlList acl, Role role, Domain domain)
        throws ACLException, Exception
    {
        grantRole(acl, role, domain.getSpecialProject());
    }

    /**
a817 12
    public void revokeHostRole(AccessControlList acl, Role role)
        throws ACLException, Exception
    {
        revokeRole(acl, role, ProjectPeer.getHostProject());
    }

    public void revokeRole(AccessControlList acl, Role role, Domain domain)
        throws ACLException, Exception
    {
        revokeRole(acl, role, domain.getSpecialProject());
    }

@


1.1.2.34
log
@Ported UserEdit--still some bugs that need to be worked out.
@
text
@d76 1
a76 1
 * @@version $Id: User.java,v 1.1.2.33 2001/02/08 01:15:46 elicia Exp $
d159 6
a249 20
    
    /**
     * Return a list of all groups to which this user belongs, not including
     * the special domain group.
     */
    public List getRegularGroups()
        throws Exception
    {
        List groups = getGroups();
        for (Iterator i = groups.iterator(); i.hasNext();)
        {
            User u = (User)i.next();
            if (u.isDomain() || u.isHost())
            {
                groups.remove(u);
            }
        }
        return groups;
    }

d263 1
a263 1
            groups.add(UserPeer.getInstance(String.valueOf(g.getUserGroupId())));
a720 21
    }

    /**
     * Returns true if this user can grant roles in the given
     * project.  Note that the grant permission implies revoke as
     * well.  
     */
    public boolean canRevokeRole(User user, Project project)
        throws Exception
    {
        boolean ok = false;
        if (user.getID().equals(getID()))
        {
            //Users may revoke their own roles.
            ok = true;
        } 
        else 
        {
            ok = hasRoleGrantPermission(project);
        }
        return ok;
@


1.1.2.35
log
@Got rid of concurrentModificationException.
@
text
@d76 1
a76 1
 * @@version $Id: User.java,v 1.1.2.34 2001/02/08 01:54:32 elicia Exp $
a252 3
        //There will probably be one fewer entry in the new list than
        //in the old, since every user belongs to one special group.
        List newGroups = new ArrayList(groups.size()-1);
d256 1
a256 1
            if (!(u.isDomain() || u.isHost()))
d258 1
a258 1
                newGroups.add(u);
d261 1
a261 1
        return newGroups;
d523 1
a523 1
//                  // TaskException would be the right thing to throw.
d535 1
a535 1
        //if (password != null) setPassword(password); //FIXME
@


1.1.2.36
log
@Concept of the "guest" user renamed to "anonymous".  Deprecated
isGuest() method, just in case it's still used in some templates.
@
text
@d76 1
a76 1
 * @@version $Id: User.java,v 1.1.2.35 2001/02/08 16:09:01 leonardr Exp $
d213 1
a213 1
    public final boolean isAnonymous()
d216 1
a216 1
        return equals(UserPeer.getAnonymousUser());
d219 1
a219 8
    /**
     * @@deprecated Use isAnonymous() instead.
     */
    public final boolean isGuest()
        throws Exception
    {
        return isAnonymous();
    }
@


1.1.2.37
log
@All the User methods we need should now be there, though there are still some commented portions.
@
text
@a62 2
import org.webmacro.engine.BuildContext;

a69 1
import org.tigris.helm.tool.HelmEmailer;
d76 1
a76 1
 * @@version $Id: User.java,v 1.1.2.36 2001/02/09 03:07:33 dlr Exp $
a162 7
    
    public String getDomainEmail()
        throws Exception
    {
        String domName = getDomain().getName();
        return getLoginName() + "@@" + domName;
    } 
a227 3
    /**
     * Forces a rebuild of the ACL for this user. Calling it on a
     * UserGroup will rebuild the ACLs of everyone in the UserGroup.*/
d362 34
a665 16
    /**
     * Returns true iff this user is visible by the given ACL.
     */
    public final boolean isViewableBy (AccessControlList acl)
        throws Exception
    {
        boolean viewable = false;
        if (acl.hasPermission("User - View", getDomain())
            || (acl.getUser().getID().equals(getID()) &&
                acl.hasPermission("User - View - Self", getDomain())))
        {
            viewable = true;
        }
        return viewable;
    }

d809 43
a851 14
   /**
    * Returns all the requestable project roles which the user does
    * not currently posess (in granted or requested form) in the given
    * project
    */
    public List getAvaliableRolesInProject (Project project)
        throws Exception
    {
        List allRoles = new Host().getProjectRoles();
        List haveRoles = getRolesInProject(project);
        haveRoles.addAll(getRequestedRolesInProject(project));
        allRoles.removeAll(haveRoles);
        return allRoles;
    }
a859 2
        //TODO: If a user has an invitation, bypass this
        //permission check.
a866 14

        //TODO: Add name to alias as per grantRole? (Such happens
        //in HEAD, but why?)

        String subject = "New role requested.";
        BuildContext ctx = TemplateInterpolator.createContext();
        ctx.put("user", this);
        ctx.put("role", role);
        ctx.put("project", project);
        String body = TemplateInterpolator.interpolate(ROLE_REQ_TMPL, ctx,
                                                       getClass());
        HelmEmailer emailer = new HelmEmailer();
        emailer.messageUsersWithProjectOwnership
            (project, subject, body.toString());
a908 8
        // TODO: Uncomment.
        // People in charge of a project should have their names
        // names in a special alias -- owner@@{project}.{domain}
        if (role.denotesOwnership() &&
            role.getType().equals(Role.PROJECT_TYPE)) {
            //AnzuTask.setOwnerAlias(this, project, true);
        }

d941 1
a941 3

        // TODO: If they no longer have any ownership roles,
        // remove them from the member list.
@


1.1.2.38
log
@Added import statement.
@
text
@d72 1
a72 1
import org.tigris.helm.tool.*;
d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.37 2001/02/10 00:35:52 leonardr Exp $
@


1.1.2.39
log
@Got rid of compile errors.
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.38 2001/02/10 01:14:02 leonardr Exp $
a84 6
     * The name of the template used to create the body of the user role 
     * request email.
     */
    private static final String ROLE_REQ_TMPL = "UserRoleRequest.wm";

    /**
d894 2
a895 2
        if (role.denotesOwner() && role.getType().equals(Role.PROJECT_TYPE)) 
        {
@


1.1.2.40
log
@Changed code to no longer use deprecated methods.
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.39 2001/02/10 02:20:48 leonardr Exp $
d523 1
a523 1
        if (!acl.hasPermission("User - Edit", getDomain()))
d560 1
a560 1
        acl.assertPermission("User - Delete", domain);
d637 1
a637 1
	if (acl.hasPermission
d641 1
a641 1
        } else if (acl.hasPermission
d644 1
a644 1
        } else if (acl.hasPermission
d671 1
a671 1
            acl.assertPermission("User - Add", getDomain());
d674 1
a674 1
            acl.assertPermission("UserGroup - Add", getDomain());
d682 1
a682 1
            acl.assertPermission("User - Delete", getDomain());
d685 1
a685 1
            acl.assertPermission("UserGroup - Delete", getDomain());
d694 1
a694 1
            ok = acl.hasPermission("User - Delete", getDomain());
d697 1
a697 1
            ok = acl.hasPermission("UserGroup - Delete", getDomain());
d706 1
a706 1
            acl.assertPermission("User - Edit - Self", getDomain());
d709 1
a709 1
            acl.assertPermission("User - Edit", getDomain());
d717 1
a717 1
            acl.assertPermission("User - View - Self", getDomain());
d720 1
a720 1
            acl.assertPermission("User - View", getDomain());
d732 1
a732 1
        getACL().assertPermission
d744 1
a744 1
        return getACL().hasPermission
d834 1
a834 1
        acl.assertPermission("Project Role - Request", project);
@


1.1.2.41
log
@Fixed user deletion.
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.40 2001/02/12 16:24:32 leonardr Exp $
d284 1
a284 1
            UserGroup u = (UserGroup)i.next();
d300 9
a308 4
        Criteria c = new Criteria()
            .addJoin(UserUsergroupPeer.USER_ID, UserPeer.USER_ID)
            .add(UserUsergroupPeer.USER_ID,getID());
        return UserPeer.doGroupSelect(c);
d560 1
a560 1
        assertDeletePermission(acl);
d574 1
@


1.1.2.42
log
@Rejiggered the edit permission checking methods.
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.41 2001/02/12 18:50:37 leonardr Exp $
a695 4
    /**
     * Throw an exception unless the provided ACL has permission sufficient
     * to edit this user's information.
     */
d699 2
a700 4
        if (!isEditableBy(acl))
        {
            throw new ACLException(acl, "User edit permission", 
                                   "Domain " + getDomain().getName(), null);
d702 2
a703 14
    }

    /**
     * Returns true iff the provided ACL has permission sufficient to
     * edit this user's information.
     */
    public boolean isEditableBy(AccessControlList acl)
        throws Exception
    {
        boolean ok = false;
        if (acl.getUserID().equals(getID()) &&
            acl.hasPermission("User - Edit - Self", getDomain()))
        {
            ok = true;
a704 6

        if (!ok && acl.hasPermission("User - Edit", getDomain()))
        {
            ok = true;
        }
        return ok;
@


1.1.2.43
log
@Extra line breaks be gone!
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.42 2001/02/12 22:47:15 leonardr Exp $
d341 1
d375 1
d394 1
@


1.1.2.44
log
@Fixing compile errors.
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.43 2001/02/12 23:35:01 dlr Exp $
d168 5
a179 5
    public boolean isDomain()
    {
        return (this instanceof DomainUserGroup);
    }
    
d182 1
a182 1
        return (this instanceof HostUserGroup);
a185 1
        throws Exception
d187 2
a188 1
        return (!isGroup() && !isNobody());
d193 1
a193 1
        return (this instanceof UserGroup);
a233 11
 
   /**
     * Determines whether the user is the special "nobody" user.
     *
     * @@return Whether the special "nobody".
     */
    public final boolean isNobody()
        throws Exception
    {
        return equals(UserPeer.getNobodyUser());
    }
d303 1
a303 1
        return UserPeer.doSelect(c);
@


1.1.2.45
log
@Added methods for approving and disapproving requested roles.
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.44 2001/02/13 03:35:34 leonardr Exp $
a880 37
    }

    /**
     * Approves an already requested role.
     */
    public void approveRole(AccessControlList acl, Role role, Project project)
        throws ACLException, Exception
    {        
        //TODO: Throw an exception if the user hadn't requested this role?
        grantRole(acl,role,project);

        //TODO: Use TemplateInterpolator
        String subject = "Requested role has been granted";
        StringBuffer messageBuf =
            new StringBuffer ("You requested the role of ");
        messageBuf.append (role.getName()).append (" on project '")
            .append("Congratulations! The role has been granted.");
        new HelmEmailer().mailUserFromSystem(this, subject, messageBuf.toString());
    }

    /**
     * Disapproves a requested role.
     */
    public void disapproveRole(AccessControlList acl, Role role, 
                               Project project)
        throws ACLException, Exception
    {        
        //TODO: Throw an exception if the user hadn't requested this role?
        revokeRole(acl, role, project);

        //TODO: Use TemplateInterpolator
        String subject = "Requested role has not been granted";
        StringBuffer messageBuf =
            new StringBuffer ("You requested the role of ");
        messageBuf.append (role.getName()).append (" on project '")
            .append("We regret to inform you that the role has not been granted.");
        new HelmEmailer().mailUserFromSystem(this, subject, messageBuf.toString());
@


1.1.2.46
log
@Patches to get user groups to play nice with the new generated peers.
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.45 2001/02/13 19:52:29 leonardr Exp $
d131 1
a131 1
        if (!u.isEmpty()) {
d133 1
a133 1
                                    "domain named " + domain.getName());
@


1.1.2.47
log
@Big wide-ranging patch being committed all at once due to network downness. Features of this patch include: lots of added and updated JavaDoc, conversion of emails to use TemplateInterpolator and HelmEmailer, rearrangement of methods, changing code that gets mappings and loops over them to code that just gets the appropriate objects from the peer using AddJoin.
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.46 2001/02/13 21:27:47 leonardr Exp $
d88 1
a88 16
    private static final String ROLE_REQUESTED_TEMPLATE = 
        "UserRoleRequest.wm";

    /**
     * The name of the template used to create the body of the requested
     * role approval email.
     */
    private static final String ROLE_REQUEST_APPROVED_TEMPLATE = 
        "RequestedRoleApproved.wm";

    /**
     * The name of the template used to create the body of the requested
     * role denial email.
     */
    private static final String ROLE_REQUEST_DENIED_TEMPLATE = 
        "RequestedRoleDenied.wm";
a99 3
    /**
     * Static initializer; initialize regular expressions.
     */
d162 1
a162 4

    /**
     * Returns this user's ID as a string.
     */
a167 11
    /**
     * Returns the ID of this user's domain as a string.
     */
    public final String getDomainID()
    {
        return String.valueOf(getDomainId());
    }

    /**
     * Returns the site email address for this user.
     */
a174 3
    /**
     * Returns true iff this user represents the users in a domain.
     */
d179 1
a179 4

    /**
     * Returns true iff this user represents the users in the host domain.
     */    
d185 6
a190 3
    /**
     * Returns true iff this user represents an admin-defined usergroup.
     */
d195 12
d208 11
a218 6
    /**
     * Returns true iff this User object represents an actual user of
     * the site who can log in.  
     */
    public boolean isBase()
        throws Exception
d220 1
a220 2
        //TODO: Check for other special accounts like postmaster, etc.
        return (!isGroup() && !isNobody());
a255 10
     * Compare this user to another object for sorting purposes.
     */
    public int compareTo(Object o)
        throws ClassCastException
    {
        User u = (User)o;
        return getRealName().compareTo(u.getRealName());
    }

    /**
d257 1
a257 2
     * UserGroup will rebuild the ACLs of everyone in the UserGroup.
     */
a265 29
    /**
     * Obtains the ACL for this user.
     */
    public AccessControlList getACL()
        throws Exception
    {
        return AccessControlList.getACL(this);
    }

    /**
     * Turns a User object representing a group of users into a UserGroup
     * object.
     */
    public UserGroup asGroup()
        throws Exception
    {
        if (isBase())
        {
            throw new Exception
                ("Attempt to transform non-group user to UserGroup.");
        } 
        return UserPeer.getGroupInstance(getID());
    }

    /**
     * Returns a list of the effective user IDs for this user. This
     * consists of the user's ID itself and ther user IDs of all groups
     * to which this user belongs.
     */
d280 1
d295 1
a295 1
            User u = (User)i.next();
d324 8
a331 2
        List users = new ArrayList(1);
        users.add(this);
d335 17
d385 19
d627 1
a627 1
    // Role and permission management - accessor methods
a668 4
    /**
     * Throws an exception unless the user has permission sufficient to
     * add this user to the database.
     */
a679 4
    /**
     * Throws an exception unless the user has permission sufficient to
     * delete this user.
     */
a690 4
    /**
     * Returns true iff the user has permission sufficient to delete
     * this user.  
     */
a738 4
    /**
     * Returns true iff the provided ACL has permission sufficient to
     * look at this user's information.  
     */
a795 33
     * Returns all projects in which this user has a role..
     */
    public List getProjectsForUser()
        throws Exception
    {        
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getID());
        List urps = UserRoleProjectPeer.doSelect(c);
        List projects = new ArrayList(urps.size());
        UserRoleProject urp;
        for (Iterator i = urps.iterator(); i.hasNext(); ) {
            urp = (UserRoleProject)i.next();
            projects.add(ProjectPeer.retrieveByPK(urp.getProjectId()));
        }
        return projects;
    }

   /**
    * Returns all the requestable project roles which the user does
    * not currently posess (in granted or requested form) in the given
    * project
    */
    public List getAvaliableRolesInProject (Project project)
        throws Exception
    {
        List allRoles = new Host().getProjectRoles();
        List haveRoles = getRolesInProject(project);
        haveRoles.addAll(getRequestedRolesInProject(project));
        allRoles.removeAll(haveRoles);
        return allRoles;
    }

    /**
d814 2
a815 2
     * Does the heavy lifting for the public getRolesInProject and
     * getRequestedRolesInProject.  
a822 1
            .addJoin(RolePeer.ROLE_ID, UserRoleProjectPeer.ROLE_ID)
d827 7
a833 1
        return RolePeer.doSelect(c);
d836 6
a841 5
    /**
     * Convenience method to send email to a user regarding a role.
     */
    private void mailUserAboutRole(String templateName, String subject,
                                   Role role, Project project)
d844 5
a848 7
        BuildContext ctx = TemplateInterpolator.createContext();
        ctx.put("user", this);
        ctx.put("role", role);
        ctx.put("project", project);
        String body = TemplateInterpolator.interpolate
            (templateName, ctx, getClass());
        new HelmEmailer().mailUserFromSystem(this, subject, body.toString());
a850 4
    //
    // Role and permission management - mutator methods
    //

d876 2
a877 2
        String body = TemplateInterpolator.interpolate
            (ROLE_REQUESTED_TEMPLATE, ctx, getClass());
d892 7
a898 3
        mailUserAboutRole(ROLE_REQUEST_APPROVED_TEMPLATE,
                          "Requested role has been granted", 
                          role, project);
d911 7
a917 3
        mailUserAboutRole(ROLE_REQUEST_DENIED_TEMPLATE,
                          "Requested role has not been granted", 
                          role, project);
d975 1
a975 4

    /**
     * Revokes from this user a role in the host.
     */
a981 3
    /**
     * Revokes from this user a role in the given domain.
     */
d989 1
a989 1
     * Revokes from this user a role in the specified project.
@


1.1.2.48
log
@Normalized copyright dates.
@
text
@d2 1
a2 1
 * Copyright (c) 2000-2001 CollabNet.  All rights reserved.
d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.47 2001/02/14 23:20:29 leonardr Exp $
@


1.1.2.49
log
@Ported ProjectMembershipRequest servlet.
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.48 2001/02/15 20:50:38 leonardr Exp $
a764 17
    }

    /**
     * Returns true iff the user has requested the given role in the
     * given project.  
     */
    public boolean hasRequestedRoleInProject(Role role, Project project)
        throws Exception
    {
        Criteria c = new Criteria()
            .add(UserRoleProjectPeer.USER_ID, getUserId())
            .add(UserRoleProjectPeer.ROLE_ID, getUserId())
            .add(UserRoleProjectPeer.PROJECT_ID, getUserId())
            .add(UserRoleProjectPeer.APPROVED_BY, 
                 UserPeer.getNobodyUser().getUserId());
        List roles = UserRoleProjectPeer.doSelect(c);
        return (!roles.isEmpty());
@


1.1.2.50
log
@'avaliable roles' should only include requestable roles.
@
text
@d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.49 2001/02/16 02:02:16 leonardr Exp $
d870 1
a870 1
        List allRoles = new Host().getRequestableProjectRoles();
@


1.1.2.51
log
@Added new imports necessitated by Torque.
@
text
@a66 1
import org.tigris.helm.om.base.*;
d79 1
a79 1
 * @@version $Id: User.java,v 1.1.2.50 2001/02/16 02:08:15 leonardr Exp $
@


1.1.2.52
log
@Added audit logging in a bunch of places.
@
text
@d80 1
a80 1
 * @@version $Id: User.java,v 1.1.2.51 2001/02/16 03:01:27 dlr Exp $
a85 30
     * Description of the audit log entry created when a user of this
     * type is added.  
     */
    private static final AUDIT_LOG_ON_ADD = "User added: ";

    /**
     * Description of the audit log entry created when a user of this
     * type is deleted.
     */
    private static final AUDIT_LOG_ON_DELETE = "User deleted: ";

    /**
     * Description of the audit log entry created when a user of this
     * type is edited.
     */
    private static final AUDIT_LOG_ON_EDIT = "User edited: ";

    /**
     * Description of the audit log entry created when a user of this
     * type is granted a role.
     */
    private static final AUDIT_LOG_ON_ROLE_GRANT = "Role granted to user: ";

    /**
     * Description of the audit log entry created when a role is
     * revoked from a user of this type.  
     */
    private static final AUDIT_LOG_ON_ROLE_REVOKE = "Role revoked from user: ";

    /**
d444 2
a445 3
        User u = add(acl, domain, realName, loginName, password, email, null, 
                     REGULAR_TYPE);
        return u;
a510 2
        AuditLog.logEvent(acl.getUser(), domain, u.AUDIT_LOG_ON_ADD 
                          + u.getLoginName());
a551 2
        AuditLog.logEvent(acl.getUser(), getDomain(), u.AUDIT_LOG_ON_EDIT
                          + u.getLoginName());
a609 2
        String message = u.AUDIT_LOG_ON_DELETE;
        String loginName = u.getLoginName();
a611 2
        AuditLog.logEvent(acl.getUser(), getDomain(), message + loginName);

a1048 3
        AuditLog.logEvent(acl.getUser(), project, AUDIT_LOG_ON_ROLE_GRANT 
                          + getLoginName() + " <- " + role.getName());
                          
a1083 2
        AuditLog.logEvent(acl.getUser(), project, AUDIT_LOG_ON_ROLE_GRANT 
                          + getLoginName() + " -> " + role.getName());
@


1.1.2.53
log
@Fixed compile errors introduced in audit logging patch.
@
text
@a72 1
import org.tigris.helm.tool.audit.AuditLog;
d80 1
a80 1
 * @@version $Id: User.java,v 1.1.2.52 2001/02/16 16:09:07 leonardr Exp $
d89 1
a89 1
    private static final String AUDIT_LOG_ON_ADD = "User added: ";
d95 1
a95 1
    private static final String AUDIT_LOG_ON_DELETE = "User deleted: ";
d101 1
a101 1
    private static final String AUDIT_LOG_ON_EDIT = "User edited: ";
d107 1
a107 1
    private static final String AUDIT_LOG_ON_ROLE_GRANT = "Role granted to user: ";
d113 1
a113 1
    private static final String AUDIT_LOG_ON_ROLE_REVOKE = "Role revoked from user: ";
d542 2
a543 2
        AuditLog.logEvent(acl.getUser(), domain, user.AUDIT_LOG_ON_ADD 
                          + user.getLoginName());
d585 2
a586 2
        AuditLog.logEvent(acl.getUser(), getDomain(), AUDIT_LOG_ON_EDIT
                          + getLoginName());
d645 2
a646 2
        String message = AUDIT_LOG_ON_DELETE;
        String loginName = getLoginName();
@


1.1.2.54
log
@Don't revoke host ownership roles from superuser.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.1.2.53 2001/02/16 16:26:36 leonardr Exp $
a297 11
     * Determines whether the user is the superuser.
     *
     * @@return Whether the superuser.
     */
    public final boolean isSuperUser()
        throws Exception
    {
        return equals(UserPeer.getSuperUser());
    }

    /**
d1117 1
a1117 1
    {        
a1118 9

        //Special case: The superuser cannot lose a role which gives
        //them ownership over the host.
        if (isSuperUser() && role.denotesOwner() 
            && role.getType().equals(Role.HOST_TYPE))
        {
            throw new Exception("Superuser cannot lose host ownership role.");
        }

@


1.1.2.55
log
@Corrected bad method call.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.1.2.54 2001/02/16 21:19:39 leonardr Exp $
d499 1
a499 1
        return add(acl, domain, realName, loginName, password, email,
@


1.1.2.56
log
@Now correctly gets the user's groups.
@
text
@d81 1
a81 1
 * @@version $Id: User.java,v 1.1.2.55 2001/02/16 22:21:40 leonardr Exp $
d413 1
a413 1
            .addJoin(UserUsergroupPeer.USER_GROUP_ID, UserPeer.USER_ID)
d415 1
a415 1
        return UserPeer.doSelect(c);        
@


