You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2018/01/05 15:40:48 UTC

[01/16] guacamole-client git commit: GUACAMOLE-394: Add guacamole_user_history table to database schema.

Repository: guacamole-client
Updated Branches:
  refs/heads/staging/0.9.14 ed6722ba5 -> 1c5951b6a


GUACAMOLE-394: Add guacamole_user_history table to database schema.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/5aa2172e
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/5aa2172e
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/5aa2172e

Branch: refs/heads/staging/0.9.14
Commit: 5aa2172eacfc066ddd925b959ca693e66eb1f35b
Parents: c991ea4
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 13:18:00 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:56 2017 -0800

----------------------------------------------------------------------
 .../schema/001-create-schema.sql                | 24 +++++++++++++++
 .../schema/upgrade/upgrade-pre-0.9.14.sql       | 24 +++++++++++++++
 .../schema/001-create-schema.sql                | 30 +++++++++++++++++++
 .../schema/upgrade/upgrade-pre-0.9.14.sql       | 30 +++++++++++++++++++
 .../schema/001-create-schema.sql                | 31 ++++++++++++++++++++
 5 files changed, 139 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/5aa2172e/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
index 1873d1c..d65bd33 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
@@ -352,6 +352,30 @@ CREATE TABLE `guacamole_connection_history` (
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
+-- User login/logout history
+--
+
+CREATE TABLE guacamole_user_history (
+
+  `history_id`           int(11)      NOT NULL AUTO_INCREMENT,
+  `user_id`              int(11)      DEFAULT NULL,
+  `username`             varchar(128) NOT NULL,
+  `remote_host`          varchar(256) DEFAULT NULL,
+  `start_date`           datetime     NOT NULL,
+  `end_date`             datetime     DEFAULT NULL,
+
+  PRIMARY KEY (history_id),
+  KEY `user_id` (`user_id`),
+  KEY `start_date` (`start_date`),
+  KEY `end_date` (`end_date`),
+
+  CONSTRAINT guacamole_user_history_ibfk_1
+    FOREIGN KEY (user_id)
+    REFERENCES guacamole_user (user_id) ON DELETE SET NULL
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
 -- User password history
 --
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/5aa2172e/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.14.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.14.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.14.sql
index 01be93a..5a0a0b2 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.14.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.14.sql
@@ -37,3 +37,27 @@ ALTER TABLE guacamole_connection
 
 ALTER TABLE guacamole_connection_history
     ADD COLUMN remote_host VARCHAR(256) DEFAULT NULL;
+
+--
+-- User login/logout history
+--
+
+CREATE TABLE guacamole_user_history (
+
+  `history_id`           int(11)      NOT NULL AUTO_INCREMENT,
+  `user_id`              int(11)      DEFAULT NULL,
+  `username`             varchar(128) NOT NULL,
+  `remote_host`          varchar(256) DEFAULT NULL,
+  `start_date`           datetime     NOT NULL,
+  `end_date`             datetime     DEFAULT NULL,
+
+  PRIMARY KEY (history_id),
+  KEY `user_id` (`user_id`),
+  KEY `start_date` (`start_date`),
+  KEY `end_date` (`end_date`),
+
+  CONSTRAINT guacamole_user_history_ibfk_1
+    FOREIGN KEY (user_id)
+    REFERENCES guacamole_user (user_id) ON DELETE SET NULL
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/5aa2172e/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
index e4015d3..4840c91 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
@@ -439,6 +439,36 @@ CREATE INDEX guacamole_connection_history_end_date
     ON guacamole_connection_history(end_date);
 
 --
+-- User login/logout history
+--
+
+CREATE TABLE guacamole_user_history (
+
+  history_id           serial       NOT NULL,
+  user_id              integer      DEFAULT NULL,
+  username             varchar(128) NOT NULL,
+  remote_host          varchar(256) DEFAULT NULL,
+  start_date           timestamptz  NOT NULL,
+  end_date             timestamptz  DEFAULT NULL,
+
+  PRIMARY KEY (history_id),
+
+  CONSTRAINT guacamole_user_history_ibfk_1
+    FOREIGN KEY (user_id)
+    REFERENCES guacamole_user (user_id) ON DELETE SET NULL
+
+);
+
+CREATE INDEX guacamole_user_history_user_id
+    ON guacamole_user_history(user_id);
+
+CREATE INDEX guacamole_user_history_start_date
+    ON guacamole_user_history(start_date);
+
+CREATE INDEX guacamole_user_history_end_date
+    ON guacamole_user_history(end_date);
+
+--
 -- User password history
 --
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/5aa2172e/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.14.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.14.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.14.sql
index 157e896..39e8e59 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.14.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.14.sql
@@ -37,3 +37,33 @@ ALTER TABLE guacamole_connection
 
 ALTER TABLE guacamole_connection_history
     ADD COLUMN remote_host VARCHAR(256) DEFAULT NULL;
+
+--
+-- User login/logout history
+--
+
+CREATE TABLE guacamole_user_history (
+
+  history_id           serial       NOT NULL,
+  user_id              integer      DEFAULT NULL,
+  username             varchar(128) NOT NULL,
+  remote_host          varchar(256) DEFAULT NULL,
+  start_date           timestamptz  NOT NULL,
+  end_date             timestamptz  DEFAULT NULL,
+
+  PRIMARY KEY (history_id),
+
+  CONSTRAINT guacamole_user_history_ibfk_1
+    FOREIGN KEY (user_id)
+    REFERENCES guacamole_user (user_id) ON DELETE SET NULL
+
+);
+
+CREATE INDEX guacamole_user_history_user_id
+    ON guacamole_user_history(user_id);
+
+CREATE INDEX guacamole_user_history_start_date
+    ON guacamole_user_history(start_date);
+
+CREATE INDEX guacamole_user_history_end_date
+    ON guacamole_user_history(end_date);

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/5aa2172e/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
index 91ba377..19d48e4 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
@@ -505,6 +505,37 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_connection_history_end_date]
 GO
 
 --
+-- User login/logout history
+--
+
+CREATE TABLE [guacamole_user_history] (
+
+    [history_id]           [int] IDENTITY(1,1) NOT NULL,
+    [user_id]              [int]               DEFAULT NULL,
+    [username]             [nvarchar](128)     NOT NULL,
+    [remote_host]          [nvarchar](256)     DEFAULT NULL,
+    [start_date]           [datetime]          NOT NULL,
+    [end_date]             [datetime]          DEFAULT NULL,
+
+    PRIMARY KEY (history_id),
+
+    CONSTRAINT FK_guacamole_user_history_user_id
+        FOREIGN KEY (user_id)
+        REFERENCES guacamole_user (user_id) ON DELETE SET NULL
+
+);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_history_user_id]
+    ON [guacamole_user_history] ([user_id]);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_history_start_date]
+    ON [guacamole_user_history] ([start_date]);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_history_end_date]
+    ON [guacamole_user_history] ([end_date]);
+GO
+
+--
 -- The user_password_history table stores password history
 -- for users, allowing for enforcing rules associated with
 -- reuse of passwords.


[07/16] guacamole-client git commit: GUACAMOLE-394: Add mapper for user login records.

Posted by vn...@apache.org.
GUACAMOLE-394: Add mapper for user login records.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/6f6b4e5d
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/6f6b4e5d
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/6f6b4e5d

Branch: refs/heads/staging/0.9.14
Commit: 6f6b4e5d960f01d934155336168b9395cf349100
Parents: 5aa2172
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 12:50:09 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../jdbc/JDBCAuthenticationProviderModule.java  |   2 +
 .../auth/jdbc/user/UserRecordMapper.java        | 113 ++++++++++++
 .../auth/jdbc/user/UserRecordMapper.xml         | 173 +++++++++++++++++++
 .../auth/jdbc/user/UserRecordMapper.xml         | 173 +++++++++++++++++++
 .../auth/jdbc/user/UserRecordMapper.xml         | 173 +++++++++++++++++++
 5 files changed, 634 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/6f6b4e5d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
index c9274dc..0f72559 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
@@ -76,6 +76,7 @@ import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileParameterMapp
 import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileService;
 import org.apache.guacamole.auth.jdbc.tunnel.RestrictedGuacamoleTunnelService;
 import org.apache.guacamole.auth.jdbc.user.PasswordRecordMapper;
+import org.apache.guacamole.auth.jdbc.user.UserRecordMapper;
 import org.mybatis.guice.MyBatisModule;
 import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
 
@@ -126,6 +127,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
         addMapperClass(SharingProfilePermissionMapper.class);
         addMapperClass(UserMapper.class);
         addMapperClass(UserPermissionMapper.class);
+        addMapperClass(UserRecordMapper.class);
         
         // Bind core implementations of guacamole-ext classes
         bind(ActiveConnectionDirectory.class);

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/6f6b4e5d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
new file mode 100644
index 0000000..68f0c94
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.user;
+
+import java.util.Collection;
+import java.util.List;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Mapper for user login activity records.
+ */
+public interface UserRecordMapper {
+
+    /**
+     * Returns a collection of all user login records associated with the user
+     * having the given username.
+     *
+     * @param username
+     *     The username of the user whose login records are to be retrieved.
+     *
+     * @return
+     *     A collection of all user login records associated with the user
+     *     having the given username. This collection will be empty if no such
+     *     user exists.
+     */
+    List<ActivityRecordModel> select(@Param("username") String username);
+
+    /**
+     * Inserts the given user login record.
+     *
+     * @param record
+     *     The user login record to insert.
+     *
+     * @return
+     *     The number of rows inserted.
+     */
+    int insert(@Param("record") ActivityRecordModel record);
+
+    /**
+     * Searches for up to <code>limit</code> user login records that contain
+     * the given terms, sorted by the given predicates, regardless of whether
+     * the data they are associated with is is readable by any particular user.
+     * This should only be called on behalf of a system administrator. If
+     * records are needed by a non-administrative user who must have explicit
+     * read rights, use searchReadable() instead.
+     *
+     * @param terms
+     *     The search terms that must match the returned records.
+     *
+     * @param sortPredicates
+     *     A list of predicates to sort the returned records by, in order of
+     *     priority.
+     *
+     * @param limit
+     *     The maximum number of records that should be returned.
+     *
+     * @return
+     *     The results of the search performed with the given parameters.
+     */
+    List<ActivityRecordModel> search(@Param("terms") Collection<ActivityRecordSearchTerm> terms,
+            @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
+            @Param("limit") int limit);
+
+    /**
+     * Searches for up to <code>limit</code> user login records that contain
+     * the given terms, sorted by the given predicates. Only records that are
+     * associated with data explicitly readable by the given user will be
+     * returned. If records are needed by a system administrator (who, by
+     * definition, does not need explicit read rights), use search() instead.
+     *
+     * @param user
+     *    The user whose permissions should determine whether a record is
+     *    returned.
+     *
+     * @param terms
+     *     The search terms that must match the returned records.
+     *
+     * @param sortPredicates
+     *     A list of predicates to sort the returned records by, in order of
+     *     priority.
+     *
+     * @param limit
+     *     The maximum number of records that should be returned.
+     *
+     * @return
+     *     The results of the search performed with the given parameters.
+     */
+    List<ActivityRecordModel> searchReadable(@Param("user") UserModel user,
+            @Param("terms") Collection<ActivityRecordSearchTerm> terms,
+            @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
+            @Param("limit") int limit);
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/6f6b4e5d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
new file mode 100644
index 0000000..0467452
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.user.UserRecordMapper" >
+
+    <!-- Result mapper for system permissions -->
+    <resultMap id="UserRecordResultMap" type="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+        <result column="remote_host" property="remoteHost" jdbcType="VARCHAR"/>
+        <result column="user_id"     property="userID"     jdbcType="INTEGER"/>
+        <result column="username"    property="username"   jdbcType="VARCHAR"/>
+        <result column="start_date"  property="startDate"  jdbcType="TIMESTAMP"/>
+        <result column="end_date"    property="endDate"    jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <!-- Select all user records from a given user -->
+    <select id="select" resultMap="UserRecordResultMap">
+
+        SELECT
+            guacamole_user_history.remote_host,
+            guacamole_user_history.user_id,
+            guacamole_user_history.username,
+            guacamole_user_history.start_date,
+            guacamole_user_history.end_date
+        FROM guacamole_user_history
+        JOIN guacamole_user ON guacamole_user_history.user_id = guacamole_user.user_id
+        WHERE
+            guacamole_user.username = #{username,jdbcType=VARCHAR}
+        ORDER BY
+            guacamole_user_history.start_date DESC,
+            guacamole_user_history.end_date DESC
+
+    </select>
+
+    <!-- Insert the given user record -->
+    <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+
+        INSERT INTO guacamole_user_history (
+            remote_host,
+            user_id,
+            username,
+            start_date,
+            end_date
+        )
+        VALUES (
+            #{record.remoteHost,jdbcType=VARCHAR},
+            (SELECT user_id FROM guacamole_user
+             WHERE username = #{record.username,jdbcType=VARCHAR}),
+            #{record.username,jdbcType=VARCHAR},
+            #{record.startDate,jdbcType=TIMESTAMP},
+            #{record.endDate,jdbcType=TIMESTAMP}
+        )
+
+    </insert>
+
+    <!-- Search for specific user records -->
+    <select id="search" resultMap="UserRecordResultMap">
+
+        SELECT
+            guacamole_user_history.remote_host,
+            guacamole_user_history.user_id,
+            guacamole_user_history.username,
+            guacamole_user_history.start_date,
+            guacamole_user_history.end_date
+        FROM guacamole_user_history
+
+        <!-- Search terms -->
+        <foreach collection="terms" item="term"
+                 open="WHERE " separator=" AND ">
+            (
+
+                guacamole_user_history.user_id IN (
+                    SELECT user_id
+                    FROM guacamole_user
+                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                )
+
+                <if test="term.startDate != null and term.endDate != null">
+                    OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
+                </if>
+
+            )
+        </foreach>
+
+        <!-- Bind sort property enum values for sake of readability -->
+        <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
+
+        <!-- Sort predicates -->
+        <foreach collection="sortPredicates" item="sortPredicate"
+                 open="ORDER BY " separator=", ">
+            <choose>
+                <when test="sortPredicate.property == START_DATE">guacamole_user_history.start_date</when>
+                <otherwise>1</otherwise>
+            </choose>
+            <if test="sortPredicate.descending">DESC</if>
+        </foreach>
+
+        LIMIT #{limit,jdbcType=INTEGER}
+
+    </select>
+
+    <!-- Search for specific user records -->
+    <select id="searchReadable" resultMap="UserRecordResultMap">
+
+        SELECT
+            guacamole_user_history.remote_host,
+            guacamole_user_history.user_id,
+            guacamole_user_history.username,
+            guacamole_user_history.start_date,
+            guacamole_user_history.end_date
+        FROM guacamole_user_history
+
+        <!-- Restrict to readable users -->
+        JOIN guacamole_user_permission ON
+                guacamole_user_history.user_id       = guacamole_user_permission.affected_user_id
+            AND guacamole_user_permission.user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_user_permission.permission = 'READ'
+
+        <!-- Search terms -->
+        <foreach collection="terms" item="term"
+                 open="WHERE " separator=" AND ">
+            (
+
+                guacamole_user_history.user_id IN (
+                    SELECT user_id
+                    FROM guacamole_user
+                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                )
+
+                <if test="term.startDate != null and term.endDate != null">
+                    OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
+                </if>
+
+            )
+        </foreach>
+
+        <!-- Bind sort property enum values for sake of readability -->
+        <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
+
+        <!-- Sort predicates -->
+        <foreach collection="sortPredicates" item="sortPredicate"
+                 open="ORDER BY " separator=", ">
+            <choose>
+                <when test="sortPredicate.property == START_DATE">guacamole_user_history.start_date</when>
+                <otherwise>1</otherwise>
+            </choose>
+            <if test="sortPredicate.descending">DESC</if>
+        </foreach>
+
+        LIMIT #{limit,jdbcType=INTEGER}
+
+    </select>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/6f6b4e5d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
new file mode 100644
index 0000000..0467452
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.user.UserRecordMapper" >
+
+    <!-- Result mapper for system permissions -->
+    <resultMap id="UserRecordResultMap" type="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+        <result column="remote_host" property="remoteHost" jdbcType="VARCHAR"/>
+        <result column="user_id"     property="userID"     jdbcType="INTEGER"/>
+        <result column="username"    property="username"   jdbcType="VARCHAR"/>
+        <result column="start_date"  property="startDate"  jdbcType="TIMESTAMP"/>
+        <result column="end_date"    property="endDate"    jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <!-- Select all user records from a given user -->
+    <select id="select" resultMap="UserRecordResultMap">
+
+        SELECT
+            guacamole_user_history.remote_host,
+            guacamole_user_history.user_id,
+            guacamole_user_history.username,
+            guacamole_user_history.start_date,
+            guacamole_user_history.end_date
+        FROM guacamole_user_history
+        JOIN guacamole_user ON guacamole_user_history.user_id = guacamole_user.user_id
+        WHERE
+            guacamole_user.username = #{username,jdbcType=VARCHAR}
+        ORDER BY
+            guacamole_user_history.start_date DESC,
+            guacamole_user_history.end_date DESC
+
+    </select>
+
+    <!-- Insert the given user record -->
+    <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+
+        INSERT INTO guacamole_user_history (
+            remote_host,
+            user_id,
+            username,
+            start_date,
+            end_date
+        )
+        VALUES (
+            #{record.remoteHost,jdbcType=VARCHAR},
+            (SELECT user_id FROM guacamole_user
+             WHERE username = #{record.username,jdbcType=VARCHAR}),
+            #{record.username,jdbcType=VARCHAR},
+            #{record.startDate,jdbcType=TIMESTAMP},
+            #{record.endDate,jdbcType=TIMESTAMP}
+        )
+
+    </insert>
+
+    <!-- Search for specific user records -->
+    <select id="search" resultMap="UserRecordResultMap">
+
+        SELECT
+            guacamole_user_history.remote_host,
+            guacamole_user_history.user_id,
+            guacamole_user_history.username,
+            guacamole_user_history.start_date,
+            guacamole_user_history.end_date
+        FROM guacamole_user_history
+
+        <!-- Search terms -->
+        <foreach collection="terms" item="term"
+                 open="WHERE " separator=" AND ">
+            (
+
+                guacamole_user_history.user_id IN (
+                    SELECT user_id
+                    FROM guacamole_user
+                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                )
+
+                <if test="term.startDate != null and term.endDate != null">
+                    OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
+                </if>
+
+            )
+        </foreach>
+
+        <!-- Bind sort property enum values for sake of readability -->
+        <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
+
+        <!-- Sort predicates -->
+        <foreach collection="sortPredicates" item="sortPredicate"
+                 open="ORDER BY " separator=", ">
+            <choose>
+                <when test="sortPredicate.property == START_DATE">guacamole_user_history.start_date</when>
+                <otherwise>1</otherwise>
+            </choose>
+            <if test="sortPredicate.descending">DESC</if>
+        </foreach>
+
+        LIMIT #{limit,jdbcType=INTEGER}
+
+    </select>
+
+    <!-- Search for specific user records -->
+    <select id="searchReadable" resultMap="UserRecordResultMap">
+
+        SELECT
+            guacamole_user_history.remote_host,
+            guacamole_user_history.user_id,
+            guacamole_user_history.username,
+            guacamole_user_history.start_date,
+            guacamole_user_history.end_date
+        FROM guacamole_user_history
+
+        <!-- Restrict to readable users -->
+        JOIN guacamole_user_permission ON
+                guacamole_user_history.user_id       = guacamole_user_permission.affected_user_id
+            AND guacamole_user_permission.user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_user_permission.permission = 'READ'
+
+        <!-- Search terms -->
+        <foreach collection="terms" item="term"
+                 open="WHERE " separator=" AND ">
+            (
+
+                guacamole_user_history.user_id IN (
+                    SELECT user_id
+                    FROM guacamole_user
+                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                )
+
+                <if test="term.startDate != null and term.endDate != null">
+                    OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
+                </if>
+
+            )
+        </foreach>
+
+        <!-- Bind sort property enum values for sake of readability -->
+        <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
+
+        <!-- Sort predicates -->
+        <foreach collection="sortPredicates" item="sortPredicate"
+                 open="ORDER BY " separator=", ">
+            <choose>
+                <when test="sortPredicate.property == START_DATE">guacamole_user_history.start_date</when>
+                <otherwise>1</otherwise>
+            </choose>
+            <if test="sortPredicate.descending">DESC</if>
+        </foreach>
+
+        LIMIT #{limit,jdbcType=INTEGER}
+
+    </select>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/6f6b4e5d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
new file mode 100644
index 0000000..fafa863
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.user.UserRecordMapper" >
+
+    <!-- Result mapper for system permissions -->
+    <resultMap id="UserRecordResultMap" type="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+        <result column="remote_host" property="remoteHost" jdbcType="VARCHAR"/>
+        <result column="user_id"     property="userID"     jdbcType="INTEGER"/>
+        <result column="username"    property="username"   jdbcType="VARCHAR"/>
+        <result column="start_date"  property="startDate"  jdbcType="TIMESTAMP"/>
+        <result column="end_date"    property="endDate"    jdbcType="TIMESTAMP"/>
+    </resultMap>
+
+    <!-- Select all user records from a given user -->
+    <select id="select" resultMap="UserRecordResultMap">
+
+        SELECT
+            [guacamole_user_history].remote_host,
+            [guacamole_user_history].user_id,
+            [guacamole_user_history].username,
+            [guacamole_user_history].start_date,
+            [guacamole_user_history].end_date
+        FROM [guacamole_user_history]
+        JOIN [guacamole_user] ON [guacamole_user_history].user_id = [guacamole_user].user_id
+        WHERE
+            [guacamole_user].username = #{username,jdbcType=VARCHAR}
+        ORDER BY
+            [guacamole_user_history].start_date DESC,
+            [guacamole_user_history].end_date DESC
+
+    </select>
+
+    <!-- Insert the given user record -->
+    <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+
+        INSERT INTO [guacamole_user_history] (
+            remote_host,
+            user_id,
+            username,
+            start_date,
+            end_date
+        )
+        VALUES (
+            #{record.remoteHost,jdbcType=VARCHAR},
+            (SELECT user_id FROM [guacamole_user]
+             WHERE username = #{record.username,jdbcType=VARCHAR}),
+            #{record.username,jdbcType=VARCHAR},
+            #{record.startDate,jdbcType=TIMESTAMP},
+            #{record.endDate,jdbcType=TIMESTAMP}
+        )
+
+    </insert>
+
+    <!-- Search for specific user records -->
+    <select id="search" resultMap="UserRecordResultMap">
+
+        SELECT
+            [guacamole_user_history].remote_host,
+            [guacamole_user_history].user_id,
+            [guacamole_user_history].username,
+            [guacamole_user_history].start_date,
+            [guacamole_user_history].end_date
+        FROM [guacamole_user_history]
+
+        <!-- Search terms -->
+        <foreach collection="terms" item="term"
+                 open="WHERE " separator=" AND ">
+            (
+
+                [guacamole_user_history].user_id IN (
+                    SELECT user_id
+                    FROM [guacamole_user]
+                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                )
+
+                <if test="term.startDate != null and term.endDate != null">
+                    OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
+                </if>
+
+            )
+        </foreach>
+
+        <!-- Bind sort property enum values for sake of readability -->
+        <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
+
+        <!-- Sort predicates -->
+        <foreach collection="sortPredicates" item="sortPredicate"
+                 open="ORDER BY " separator=", ">
+            <choose>
+                <when test="sortPredicate.property == START_DATE">[guacamole_user_history].start_date</when>
+                <otherwise>1</otherwise>
+            </choose>
+            <if test="sortPredicate.descending">DESC</if>
+        </foreach>
+
+        LIMIT #{limit,jdbcType=INTEGER}
+
+    </select>
+
+    <!-- Search for specific user records -->
+    <select id="searchReadable" resultMap="UserRecordResultMap">
+
+        SELECT
+            [guacamole_user_history].remote_host,
+            [guacamole_user_history].user_id,
+            [guacamole_user_history].username,
+            [guacamole_user_history].start_date,
+            [guacamole_user_history].end_date
+        FROM [guacamole_user_history]
+
+        <!-- Restrict to readable users -->
+        JOIN [guacamole_user_permission] ON
+                [guacamole_user_history].user_id       = [guacamole_user_permission].affected_user_id
+            AND [guacamole_user_permission].user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND [guacamole_user_permission].permission = 'READ'
+
+        <!-- Search terms -->
+        <foreach collection="terms" item="term"
+                 open="WHERE " separator=" AND ">
+            (
+
+                [guacamole_user_history].user_id IN (
+                    SELECT user_id
+                    FROM [guacamole_user]
+                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                )
+
+                <if test="term.startDate != null and term.endDate != null">
+                    OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
+                </if>
+
+            )
+        </foreach>
+
+        <!-- Bind sort property enum values for sake of readability -->
+        <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
+
+        <!-- Sort predicates -->
+        <foreach collection="sortPredicates" item="sortPredicate"
+                 open="ORDER BY " separator=", ">
+            <choose>
+                <when test="sortPredicate.property == START_DATE">[guacamole_user_history].start_date</when>
+                <otherwise>1</otherwise>
+            </choose>
+            <if test="sortPredicate.descending">DESC</if>
+        </foreach>
+
+        LIMIT #{limit,jdbcType=INTEGER}
+
+    </select>
+
+</mapper>


[05/16] guacamole-client git commit: GUACAMOLE-394: Cover both main object ID and "start_date" columns with an index for sake of correlated MAX(start_date) history queries.

Posted by vn...@apache.org.
GUACAMOLE-394: Cover both main object ID and "start_date" columns with an index for sake of correlated MAX(start_date) history queries.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/dbd5b982
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/dbd5b982
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/dbd5b982

Branch: refs/heads/staging/0.9.14
Commit: dbd5b982508ce098f3d88f708402820dac3b6188
Parents: 5805471
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Dec 11 23:11:57 2017 -0800
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../schema/001-create-schema.sql                          |  2 ++
 .../schema/upgrade/upgrade-pre-0.9.14.sql                 |  7 +++++++
 .../schema/001-create-schema.sql                          |  6 ++++++
 .../schema/upgrade/upgrade-pre-0.9.14.sql                 | 10 ++++++++++
 .../schema/001-create-schema.sql                          |  6 ++++++
 5 files changed, 31 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dbd5b982/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
index d65bd33..f26d2cc 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
@@ -336,6 +336,7 @@ CREATE TABLE `guacamole_connection_history` (
   KEY `sharing_profile_id` (`sharing_profile_id`),
   KEY `start_date` (`start_date`),
   KEY `end_date` (`end_date`),
+  KEY `connection_start_date` (`connection_id`, `start_date`),
 
   CONSTRAINT `guacamole_connection_history_ibfk_1`
     FOREIGN KEY (`user_id`)
@@ -368,6 +369,7 @@ CREATE TABLE guacamole_user_history (
   KEY `user_id` (`user_id`),
   KEY `start_date` (`start_date`),
   KEY `end_date` (`end_date`),
+  KEY `user_start_date` (`user_id`, `start_date`),
 
   CONSTRAINT guacamole_user_history_ibfk_1
     FOREIGN KEY (user_id)

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dbd5b982/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.14.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.14.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.14.sql
index 5a0a0b2..ee586bf 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.14.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.14.sql
@@ -39,6 +39,12 @@ ALTER TABLE guacamole_connection_history
     ADD COLUMN remote_host VARCHAR(256) DEFAULT NULL;
 
 --
+-- Add covering index for connection history connection and start date
+--
+
+ALTER TABLE guacamole_connection_history ADD KEY (connection_id, start_date);
+
+--
 -- User login/logout history
 --
 
@@ -55,6 +61,7 @@ CREATE TABLE guacamole_user_history (
   KEY `user_id` (`user_id`),
   KEY `start_date` (`start_date`),
   KEY `end_date` (`end_date`),
+  KEY `user_start_date` (`user_id`, `start_date`),
 
   CONSTRAINT guacamole_user_history_ibfk_1
     FOREIGN KEY (user_id)

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dbd5b982/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
index 4840c91..97780a5 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
@@ -438,6 +438,9 @@ CREATE INDEX guacamole_connection_history_start_date
 CREATE INDEX guacamole_connection_history_end_date
     ON guacamole_connection_history(end_date);
 
+CREATE INDEX guacamole_connection_history_connection_id_start_date
+    ON guacamole_connection_history(connection_id, start_date);
+
 --
 -- User login/logout history
 --
@@ -468,6 +471,9 @@ CREATE INDEX guacamole_user_history_start_date
 CREATE INDEX guacamole_user_history_end_date
     ON guacamole_user_history(end_date);
 
+CREATE INDEX guacamole_user_history_user_id_start_date
+    ON guacamole_user_history(user_id, start_date);
+
 --
 -- User password history
 --

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dbd5b982/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.14.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.14.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.14.sql
index 39e8e59..534d4dc 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.14.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.14.sql
@@ -39,6 +39,13 @@ ALTER TABLE guacamole_connection_history
     ADD COLUMN remote_host VARCHAR(256) DEFAULT NULL;
 
 --
+-- Add covering index for connection history connection and start date
+--
+
+CREATE INDEX guacamole_connection_history_connection_id_start_date
+    ON guacamole_connection_history(connection_id, start_date);
+
+--
 -- User login/logout history
 --
 
@@ -67,3 +74,6 @@ CREATE INDEX guacamole_user_history_start_date
 
 CREATE INDEX guacamole_user_history_end_date
     ON guacamole_user_history(end_date);
+
+CREATE INDEX guacamole_user_history_user_id_start_date
+    ON guacamole_user_history(user_id, start_date);

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dbd5b982/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
index 19d48e4..060503a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
@@ -502,6 +502,9 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_connection_history_start_date]
 
 CREATE NONCLUSTERED INDEX [IX_guacamole_connection_history_end_date]
     ON [guacamole_connection_history] ([end_date]);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_connection_history_connection_id_start_date]
+    ON [guacamole_connection_history] ([connection_id], [start_date]);
 GO
 
 --
@@ -533,6 +536,9 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_user_history_start_date]
 
 CREATE NONCLUSTERED INDEX [IX_guacamole_user_history_end_date]
     ON [guacamole_user_history] ([end_date]);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_history_user_id_start_date]
+    ON [guacamole_user_history] ([user_id], [start_date]);
 GO
 
 --


[06/16] guacamole-client git commit: GUACAMOLE-394: Automatically insert user history records upon login.

Posted by vn...@apache.org.
GUACAMOLE-394: Automatically insert user history records upon login.

Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/446a9d0e
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/446a9d0e
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/446a9d0e

Branch: refs/heads/staging/0.9.14
Commit: 446a9d0e12d99e93be614ecac49870c9484a6dce
Parents: 7e8acca
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 14:49:18 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../auth/jdbc/user/ModeledUserContext.java      | 26 ++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/446a9d0e/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
index fc2c972..0bf01fb 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
@@ -26,9 +26,11 @@ import org.apache.guacamole.auth.jdbc.connection.ConnectionDirectory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import java.util.Collection;
+import java.util.Date;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
 import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionDirectory;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
 import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordSet;
 import org.apache.guacamole.auth.jdbc.connection.ModeledConnection;
 import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
@@ -44,7 +46,6 @@ import org.apache.guacamole.net.auth.ConnectionGroup;
 import org.apache.guacamole.net.auth.Directory;
 import org.apache.guacamole.net.auth.SharingProfile;
 import org.apache.guacamole.net.auth.User;
-import org.apache.guacamole.net.auth.simple.SimpleActivityRecordSet;
 
 /**
  * UserContext implementation which is driven by an arbitrary, underlying
@@ -105,7 +106,18 @@ public class ModeledUserContext extends RestrictedObject
      */
     @Inject
     private Provider<UserRecordSet> userRecordSetProvider;
-    
+
+    /**
+     * Mapper for user login records.
+     */
+    @Inject
+    private UserRecordMapper userRecordMapper;
+
+    /**
+     * The activity record associated with this user's Guacamole session.
+     */
+    private ActivityRecordModel userRecord;
+
     @Override
     public void init(ModeledAuthenticatedUser currentUser) {
 
@@ -118,6 +130,16 @@ public class ModeledUserContext extends RestrictedObject
         sharingProfileDirectory.init(currentUser);
         activeConnectionDirectory.init(currentUser);
 
+        // Create login record for user
+        userRecord = new ActivityRecordModel();
+        userRecord.setUserID(currentUser.getUser().getModel().getObjectID());
+        userRecord.setUsername(currentUser.getIdentifier());
+        userRecord.setStartDate(new Date());
+        userRecord.setRemoteHost(currentUser.getCredentials().getRemoteHostname());
+
+        // Insert record representing login
+        userRecordMapper.insert(userRecord);
+
     }
 
     @Override


[08/16] guacamole-client git commit: GUACAMOLE-394: History must be LEFT JOINed when calculating last active date, or inactive connections will disappear entirely.

Posted by vn...@apache.org.
GUACAMOLE-394: History must be LEFT JOINed when calculating last active date, or inactive connections will disappear entirely.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/a3dd9199
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/a3dd9199
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/a3dd9199

Branch: refs/heads/staging/0.9.14
Commit: a3dd919940a92fc8922b894f251c0667352f4c42
Parents: 6f6b4e5
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 12:58:02 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml | 6 +++---
 .../apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml | 6 +++---
 .../apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml | 6 +++---
 3 files changed, 9 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a3dd9199/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index 14b739e..7c20935 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -103,7 +103,7 @@
             failover_only,
             MAX(start_date) AS last_active
         FROM guacamole_connection
-        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
+        LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
         WHERE guacamole_connection.connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
@@ -140,7 +140,7 @@
             MAX(start_date) AS last_active
         FROM guacamole_connection
         JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
-        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
+        LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
         WHERE guacamole_connection.connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
@@ -180,7 +180,7 @@
             failover_only,
             MAX(start_date) AS last_active
         FROM guacamole_connection
-        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
+        LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
         WHERE 
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a3dd9199/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index 09bd510..b9356b0 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -103,7 +103,7 @@
             failover_only,
             MAX(start_date) AS last_active
         FROM guacamole_connection
-        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
+        LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
         WHERE guacamole_connection.connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
@@ -140,7 +140,7 @@
             MAX(start_date) AS last_active
         FROM guacamole_connection
         JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
-        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
+        LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
         WHERE guacamole_connection.connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
@@ -180,7 +180,7 @@
             failover_only,
             MAX(start_date) AS last_active
         FROM guacamole_connection
-        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
+        LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
         WHERE 
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a3dd9199/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index d27b528..b31b45f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -103,7 +103,7 @@
             failover_only,
             MAX(start_date) AS last_active
         FROM [guacamole_connection]
-        JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
+        LEFT JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
         WHERE [guacamole_connection].connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
@@ -140,7 +140,7 @@
             MAX(start_date) AS last_active
         FROM [guacamole_connection]
         JOIN [guacamole_connection_permission] ON [guacamole_connection_permission].connection_id = [guacamole_connection].connection_id
-        JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
+        LEFT JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
         WHERE [guacamole_connection].connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
@@ -180,7 +180,7 @@
             failover_only,
             MAX(start_date) AS last_active
         FROM [guacamole_connection]
-        JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
+        LEFT JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
         WHERE 
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>


[03/16] guacamole-client git commit: GUACAMOLE-394: Pull connection last active time from history records.

Posted by vn...@apache.org.
GUACAMOLE-394: Pull connection last active time from history records.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/3d7b8ee8
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/3d7b8ee8
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/3d7b8ee8

Branch: refs/heads/staging/0.9.14
Commit: 3d7b8ee89b278e7bfc0ccad1fa78092450761086
Parents: b0553d5
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 11 19:47:59 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:56 2017 -0800

----------------------------------------------------------------------
 .../auth/jdbc/connection/ConnectionModel.java   | 33 +++++++++++++++++++
 .../auth/jdbc/connection/ModeledConnection.java |  2 +-
 .../auth/jdbc/connection/ConnectionMapper.xml   | 34 +++++++++++++-------
 .../auth/jdbc/connection/ConnectionMapper.xml   | 34 +++++++++++++-------
 .../auth/jdbc/connection/ConnectionMapper.xml   | 34 +++++++++++++-------
 5 files changed, 100 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/3d7b8ee8/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionModel.java
index 788daa1..da45402 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionModel.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionModel.java
@@ -19,6 +19,7 @@
 
 package org.apache.guacamole.auth.jdbc.connection;
 
+import java.util.Date;
 import java.util.HashSet;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.base.ChildObjectModel;
@@ -93,6 +94,12 @@ public class ConnectionModel extends ChildObjectModel {
     private EncryptionMethod proxyEncryptionMethod;
 
     /**
+     * The date and time that this connection was last used, or null if this
+     * connection has never been used.
+     */
+    private Date lastActive;
+
+    /**
      * Creates a new, empty connection.
      */
     public ConnectionModel() {
@@ -341,6 +348,32 @@ public class ConnectionModel extends ChildObjectModel {
         this.sharingProfileIdentifiers = sharingProfileIdentifiers;
     }
 
+    /**
+     * Returns the date and time that this connection was last used, or null if
+     * this connection has never been used.
+     *
+     * @return
+     *     The date and time that this connection was last used, or null if this
+     *     connection has never been used.
+     */
+    public Date getLastActive() {
+        return lastActive;
+    }
+
+    /**
+     * Sets the date and time that this connection was last used. This value is
+     * expected to be set automatically via queries, derived from connection
+     * history records. It does NOT correspond to an actual column, and values
+     * set manually through invoking this function will not persist.
+     *
+     * @param lastActive
+     *     The date and time that this connection was last used, or null if this
+     *     connection has never been used.
+     */
+    public void setLastActive(Date lastActive) {
+        this.lastActive = lastActive;
+    }
+
     @Override
     public String getIdentifier() {
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/3d7b8ee8/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java
index c596b27..eb392bc 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java
@@ -235,7 +235,7 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
 
     @Override
     public Date getLastActive() {
-        return null;
+        return getModel().getLastActive();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/3d7b8ee8/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index 97c2e54..14b739e 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -39,6 +39,7 @@
                 javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
         <result column="connection_weight"        property="connectionWeight"      jdbcType="INTEGER"/>
         <result column="failover_only"            property="failoverOnly"          jdbcType="BOOLEAN"/>
+        <result column="last_active"              property="lastActive"            jdbcType="TIMESTAMP"/>
 
         <!-- Associated sharing profiles -->
         <collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
@@ -89,8 +90,8 @@
             resultSets="connections,sharingProfiles">
 
         SELECT
-            connection_id,
-            connection_name,
+            guacamole_connection.connection_id,
+            guacamole_connection.connection_name,
             parent_id,
             protocol,
             max_connections,
@@ -99,13 +100,16 @@
             proxy_port,
             proxy_encryption_method,
             connection_weight,
-            failover_only
+            failover_only,
+            MAX(start_date) AS last_active
         FROM guacamole_connection
-        WHERE connection_id IN
+        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
+        WHERE guacamole_connection.connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
-            </foreach>;
+            </foreach>
+        GROUP BY guacamole_connection.connection_id;
 
         SELECT primary_connection_id, sharing_profile_id
         FROM guacamole_sharing_profile
@@ -123,7 +127,7 @@
 
         SELECT
             guacamole_connection.connection_id,
-            connection_name,
+            guacamole_connection.connection_name,
             parent_id,
             protocol,
             max_connections,
@@ -132,16 +136,19 @@
             proxy_port,
             proxy_encryption_method,
             connection_weight,
-            failover_only
+            failover_only,
+            MAX(start_date) AS last_active
         FROM guacamole_connection
         JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
+        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
         WHERE guacamole_connection.connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
             AND user_id = #{user.objectID,jdbcType=INTEGER}
-            AND permission = 'READ';
+            AND permission = 'READ'
+        GROUP BY guacamole_connection.connection_id;
 
         SELECT primary_connection_id, guacamole_sharing_profile.sharing_profile_id
         FROM guacamole_sharing_profile
@@ -160,8 +167,8 @@
     <select id="selectOneByName" resultMap="ConnectionResultMap">
 
         SELECT
-            connection_id,
-            connection_name,
+            guacamole_connection.connection_id,
+            guacamole_connection.connection_name,
             parent_id,
             protocol,
             max_connections,
@@ -170,12 +177,15 @@
             proxy_port,
             proxy_encryption_method,
             connection_weight,
-            failover_only
+            failover_only,
+            MAX(start_date) AS last_active
         FROM guacamole_connection
+        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
         WHERE 
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND connection_name = #{name,jdbcType=VARCHAR}
+            AND guacamole_connection.connection_name = #{name,jdbcType=VARCHAR}
+        GROUP BY guacamole_connection.connection_id
 
     </select>
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/3d7b8ee8/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index dd9265d..09bd510 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -39,6 +39,7 @@
                 javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
         <result column="connection_weight"        property="connectionWeight"      jdbcType="INTEGER"/>
         <result column="failover_only"            property="failoverOnly"          jdbcType="BOOLEAN"/>
+        <result column="last_active"              property="lastActive"            jdbcType="TIMESTAMP"/>
 
         <!-- Associated sharing profiles -->
         <collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
@@ -89,8 +90,8 @@
             resultSets="connections,sharingProfiles">
 
         SELECT
-            connection_id,
-            connection_name,
+            guacamole_connection.connection_id,
+            guacamole_connection.connection_name,
             parent_id,
             protocol,
             max_connections,
@@ -99,13 +100,16 @@
             proxy_port,
             proxy_encryption_method,
             connection_weight,
-            failover_only
+            failover_only,
+            MAX(start_date) AS last_active
         FROM guacamole_connection
-        WHERE connection_id IN
+        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
+        WHERE guacamole_connection.connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
-            </foreach>;
+            </foreach>
+        GROUP BY guacamole_connection.connection_id;
 
         SELECT primary_connection_id, sharing_profile_id
         FROM guacamole_sharing_profile
@@ -123,7 +127,7 @@
 
         SELECT
             guacamole_connection.connection_id,
-            connection_name,
+            guacamole_connection.connection_name,
             parent_id,
             protocol,
             max_connections,
@@ -132,16 +136,19 @@
             proxy_port,
             proxy_encryption_method,
             connection_weight,
-            failover_only
+            failover_only,
+            MAX(start_date) AS last_active
         FROM guacamole_connection
         JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
+        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
         WHERE guacamole_connection.connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
             AND user_id = #{user.objectID,jdbcType=INTEGER}
-            AND permission = 'READ';
+            AND permission = 'READ'
+        GROUP BY guacamole_connection.connection_id;
 
         SELECT primary_connection_id, guacamole_sharing_profile.sharing_profile_id
         FROM guacamole_sharing_profile
@@ -160,8 +167,8 @@
     <select id="selectOneByName" resultMap="ConnectionResultMap">
 
         SELECT
-            connection_id,
-            connection_name,
+            guacamole_connection.connection_id,
+            guacamole_connection.connection_name,
             parent_id,
             protocol,
             max_connections,
@@ -170,12 +177,15 @@
             proxy_port,
             proxy_encryption_method,
             connection_weight,
-            failover_only
+            failover_only,
+            MAX(start_date) AS last_active
         FROM guacamole_connection
+        JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
         WHERE 
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND connection_name = #{name,jdbcType=VARCHAR}
+            AND guacamole_connection.connection_name = #{name,jdbcType=VARCHAR}
+        GROUP BY guacamole_connection.connection_id
 
     </select>
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/3d7b8ee8/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index 3e6819f..d27b528 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -39,6 +39,7 @@
                 javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
         <result column="connection_weight"        property="connectionWeight"      jdbcType="INTEGER"/>
         <result column="failover_only"            property="failoverOnly"          jdbcType="BOOLEAN"/>
+        <result column="last_active"              property="lastActive"            jdbcType="TIMESTAMP"/>
 
         <!-- Associated sharing profiles -->
         <collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
@@ -89,8 +90,8 @@
             resultSets="connections,sharingProfiles">
 
         SELECT
-            connection_id,
-            connection_name,
+            [guacamole_connection].connection_id,
+            [guacamole_connection].connection_name,
             parent_id,
             protocol,
             max_connections,
@@ -99,13 +100,16 @@
             proxy_port,
             proxy_encryption_method,
             connection_weight,
-            failover_only
+            failover_only,
+            MAX(start_date) AS last_active
         FROM [guacamole_connection]
-        WHERE connection_id IN
+        JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
+        WHERE [guacamole_connection].connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
-            </foreach>;
+            </foreach>
+        GROUP BY [guacamole_connection].connection_id;
 
         SELECT primary_connection_id, sharing_profile_id
         FROM [guacamole_sharing_profile]
@@ -123,7 +127,7 @@
 
         SELECT
             [guacamole_connection].connection_id,
-            connection_name,
+            [guacamole_connection].connection_name,
             parent_id,
             protocol,
             max_connections,
@@ -132,16 +136,19 @@
             proxy_port,
             proxy_encryption_method,
             connection_weight,
-            failover_only
+            failover_only,
+            MAX(start_date) AS last_active
         FROM [guacamole_connection]
         JOIN [guacamole_connection_permission] ON [guacamole_connection_permission].connection_id = [guacamole_connection].connection_id
+        JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
         WHERE [guacamole_connection].connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
             AND user_id = #{user.objectID,jdbcType=INTEGER}
-            AND permission = 'READ';
+            AND permission = 'READ'
+        GROUP BY [guacamole_connection].connection_id;
 
         SELECT primary_connection_id, [guacamole_sharing_profile].sharing_profile_id
         FROM [guacamole_sharing_profile]
@@ -160,8 +167,8 @@
     <select id="selectOneByName" resultMap="ConnectionResultMap">
 
         SELECT
-            connection_id,
-            connection_name,
+            [guacamole_connection].connection_id,
+            [guacamole_connection].connection_name,
             parent_id,
             protocol,
             max_connections,
@@ -170,12 +177,15 @@
             proxy_port,
             proxy_encryption_method,
             connection_weight,
-            failover_only
+            failover_only,
+            MAX(start_date) AS last_active
         FROM [guacamole_connection]
+        JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
         WHERE 
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND connection_name = #{name,jdbcType=VARCHAR}
+            AND [guacamole_connection].connection_name = #{name,jdbcType=VARCHAR}
+        GROUP BY [guacamole_connection].connection_id
 
     </select>
 


[04/16] guacamole-client git commit: GUACAMOLE-394: Use subquery for querying MAX() via SQL Server.

Posted by vn...@apache.org.
GUACAMOLE-394: Use subquery for querying MAX() via SQL Server.

Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/394a2898
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/394a2898
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/394a2898

Branch: refs/heads/staging/0.9.14
Commit: 394a289879dba9273f976a9174ad4eec45b674c2
Parents: dbd5b98
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Dec 11 23:15:53 2017 -0800
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../auth/jdbc/connection/ConnectionMapper.xml   | 28 ++++++++++++--------
 .../guacamole/auth/jdbc/user/UserMapper.xml     | 25 ++++++++++-------
 2 files changed, 33 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/394a2898/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index 7e0e7fd..19c3912 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -101,15 +101,17 @@
             proxy_encryption_method,
             connection_weight,
             failover_only,
-            MAX(start_date) AS last_active
+            (
+                SELECT MAX(start_date)
+                FROM [guacamole_connection_history]
+                WHERE [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
+            ) AS last_active
         FROM [guacamole_connection]
-        LEFT JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
         WHERE [guacamole_connection].connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
-            </foreach>
-        GROUP BY [guacamole_connection].connection_id;
+            </foreach>;
 
         SELECT primary_connection_id, sharing_profile_id
         FROM [guacamole_sharing_profile]
@@ -137,18 +139,20 @@
             proxy_encryption_method,
             connection_weight,
             failover_only,
-            MAX(start_date) AS last_active
+            (
+                SELECT MAX(start_date)
+                FROM [guacamole_connection_history]
+                WHERE [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
+            ) AS last_active
         FROM [guacamole_connection]
         JOIN [guacamole_connection_permission] ON [guacamole_connection_permission].connection_id = [guacamole_connection].connection_id
-        LEFT JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
         WHERE [guacamole_connection].connection_id IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
             AND [guacamole_connection_permission].user_id = #{user.objectID,jdbcType=INTEGER}
-            AND permission = 'READ'
-        GROUP BY [guacamole_connection].connection_id;
+            AND permission = 'READ';
 
         SELECT primary_connection_id, [guacamole_sharing_profile].sharing_profile_id
         FROM [guacamole_sharing_profile]
@@ -178,14 +182,16 @@
             proxy_encryption_method,
             connection_weight,
             failover_only,
-            MAX(start_date) AS last_active
+            (
+                SELECT MAX(start_date)
+                FROM [guacamole_connection_history]
+                WHERE [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
+            ) AS last_active
         FROM [guacamole_connection]
-        LEFT JOIN [guacamole_connection_history] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
         WHERE 
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
             AND [guacamole_connection].connection_name = #{name,jdbcType=VARCHAR}
-        GROUP BY [guacamole_connection].connection_id
 
     </select>
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/394a2898/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
index ec60632..24db013 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
@@ -80,15 +80,17 @@
             email_address,
             organization,
             organizational_role,
-            MAX(start_date) AS last_active
+            (
+                SELECT MAX(start_date)
+                FROM [guacamole_user_history]
+                WHERE [guacamole_user_history].user_id = [guacamole_user].user_id
+            ) AS last_active
         FROM [guacamole_user]
-        LEFT JOIN [guacamole_user_history] ON [guacamole_user_history].user_id = [guacamole_user].user_id
         WHERE [guacamole_user].username IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
-            </foreach>
-        GROUP BY [guacamole_user].user_id
+            </foreach>;
 
     </select>
 
@@ -112,10 +114,13 @@
             email_address,
             organization,
             organizational_role,
-            MAX(start_date) AS last_active
+            (
+                SELECT MAX(start_date)
+                FROM [guacamole_user_history]
+                WHERE [guacamole_user_history].user_id = [guacamole_user].user_id
+            ) AS last_active
         FROM [guacamole_user]
         JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id
-        LEFT JOIN [guacamole_user_history] ON [guacamole_user_history].user_id = [guacamole_user].user_id
         WHERE [guacamole_user].username IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
@@ -123,7 +128,6 @@
             </foreach>
             AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
             AND permission = 'READ'
-        GROUP BY [guacamole_user].user_id
 
     </select>
 
@@ -147,12 +151,15 @@
             email_address,
             organization,
             organizational_role,
-            MAX(start_date) AS last_active
+            (
+                SELECT MAX(start_date)
+                FROM [guacamole_user_history]
+                WHERE [guacamole_user_history].user_id = [guacamole_user].user_id
+            ) AS last_active
         FROM [guacamole_user]
         LEFT JOIN [guacamole_user_history] ON [guacamole_user_history].user_id = [guacamole_user].user_id
         WHERE
             [guacamole_user].username = #{username,jdbcType=VARCHAR}
-        GROUP BY [guacamole_user].user_id
 
     </select>
 


[10/16] guacamole-client git commit: GUACAMOLE-394: Map last active date for users to timestamp.

Posted by vn...@apache.org.
GUACAMOLE-394: Map last active date for users to timestamp.

Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/adf016a0
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/adf016a0
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/adf016a0

Branch: refs/heads/staging/0.9.14
Commit: adf016a005cd2c797f7d5e566b4e266770b3e174
Parents: 8694bc8
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 13:33:29 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java  | 2 +-
 .../java/org/apache/guacamole/auth/jdbc/user/UserModel.java    | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/adf016a0/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
index 7d80fac..b039a4e 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
@@ -795,7 +795,7 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
     }
 
     @Override
-    public Date getLastActive() {
+    public Timestamp getLastActive() {
         return getModel().getLastActive();
     }
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/adf016a0/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
index a4f9c7a..a6cf997 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
@@ -118,7 +118,7 @@ public class UserModel extends ObjectModel {
      * The date and time that this user was last active, or null if this user
      * has never logged in.
      */
-    private Date lastActive;
+    private Timestamp lastActive;
 
     /**
      * Creates a new, empty user.
@@ -479,7 +479,7 @@ public class UserModel extends ObjectModel {
      *     The date and time that this user was last active, or null if this
      *     user has never logged in.
      */
-    public Date getLastActive() {
+    public Timestamp getLastActive() {
         return lastActive;
     }
 
@@ -493,7 +493,7 @@ public class UserModel extends ObjectModel {
      *     The date and time that this user was last active, or null if this
      *     user has never logged in.
      */
-    public void setLastActive(Date lastActive) {
+    public void setLastActive(Timestamp lastActive) {
         this.lastActive = lastActive;
     }
 


[16/16] guacamole-client git commit: GUACAMOLE-394: Merge add support for recording user login/logout history to database auth.

Posted by vn...@apache.org.
GUACAMOLE-394: Merge add support for recording user login/logout history to database auth.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/1c5951b6
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/1c5951b6
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/1c5951b6

Branch: refs/heads/staging/0.9.14
Commit: 1c5951b6ac322a0d1e87ab787803275438d53983
Parents: ed6722b 394a289
Author: Nick Couchman <vn...@apache.org>
Authored: Fri Jan 5 10:38:12 2018 -0500
Committer: Nick Couchman <vn...@apache.org>
Committed: Fri Jan 5 10:38:12 2018 -0500

----------------------------------------------------------------------
 .../jdbc/JDBCAuthenticationProviderModule.java  |   2 +
 .../auth/jdbc/base/ActivityRecordModel.java     | 193 ++++++++++++
 .../jdbc/base/ActivityRecordSearchTerm.java     | 291 +++++++++++++++++++
 .../jdbc/base/ActivityRecordSortPredicate.java  |  77 +++++
 .../auth/jdbc/base/ModeledActivityRecord.java   |  73 +++++
 .../jdbc/base/ModeledActivityRecordSet.java     | 132 +++++++++
 .../auth/jdbc/connection/ConnectionModel.java   |  33 +++
 .../jdbc/connection/ConnectionRecordMapper.java |  10 +-
 .../jdbc/connection/ConnectionRecordModel.java  | 135 +--------
 .../connection/ConnectionRecordSearchTerm.java  | 291 -------------------
 .../jdbc/connection/ConnectionRecordSet.java    |  69 +----
 .../ConnectionRecordSortPredicate.java          |  77 -----
 .../auth/jdbc/connection/ConnectionService.java |   6 +-
 .../auth/jdbc/connection/ModeledConnection.java |   2 +-
 .../connection/ModeledConnectionRecord.java     |  31 +-
 .../guacamole/auth/jdbc/user/ModeledUser.java   |  12 +-
 .../auth/jdbc/user/ModeledUserContext.java      |  41 ++-
 .../guacamole/auth/jdbc/user/UserModel.java     |  32 ++
 .../auth/jdbc/user/UserRecordMapper.java        | 124 ++++++++
 .../guacamole/auth/jdbc/user/UserRecordSet.java |  59 ++++
 .../guacamole/auth/jdbc/user/UserService.java   | 133 ++++++++-
 .../schema/001-create-schema.sql                |  26 ++
 .../schema/upgrade/upgrade-pre-0.9.14.sql       |  31 ++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  36 ++-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  32 +-
 .../auth/jdbc/user/UserRecordMapper.xml         | 187 ++++++++++++
 .../schema/001-create-schema.sql                |  36 +++
 .../schema/upgrade/upgrade-pre-0.9.14.sql       |  40 +++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  36 ++-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  32 +-
 .../auth/jdbc/user/UserRecordMapper.xml         | 187 ++++++++++++
 .../schema/001-create-schema.sql                |  37 +++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  38 ++-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  41 ++-
 .../auth/jdbc/user/UserRecordMapper.xml         | 187 ++++++++++++
 35 files changed, 2097 insertions(+), 672 deletions(-)
----------------------------------------------------------------------



[02/16] guacamole-client git commit: GUACAMOLE-394: Split ConnectionRecord model and ModeledConnectionRecord into ActivityRecordModel and ModeledActivityRecord, etc. mirroring changes to guacamole-ext.

Posted by vn...@apache.org.
GUACAMOLE-394: Split ConnectionRecord model and ModeledConnectionRecord into ActivityRecordModel and ModeledActivityRecord, etc. mirroring changes to guacamole-ext.

Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/c991ea46
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/c991ea46
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/c991ea46

Branch: refs/heads/staging/0.9.14
Commit: c991ea46bc406dbf3973ebffb7a374e71379229e
Parents: 3d7b8ee
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 12:18:05 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:56 2017 -0800

----------------------------------------------------------------------
 .../auth/jdbc/base/ActivityRecordModel.java     | 167 +++++++++++
 .../jdbc/base/ActivityRecordSearchTerm.java     | 291 +++++++++++++++++++
 .../jdbc/base/ActivityRecordSortPredicate.java  |  77 +++++
 .../auth/jdbc/base/ModeledActivityRecord.java   |  73 +++++
 .../jdbc/connection/ConnectionRecordMapper.java |  10 +-
 .../jdbc/connection/ConnectionRecordModel.java  | 135 +--------
 .../connection/ConnectionRecordSearchTerm.java  | 291 -------------------
 .../jdbc/connection/ConnectionRecordSet.java    |  14 +-
 .../ConnectionRecordSortPredicate.java          |  77 -----
 .../auth/jdbc/connection/ConnectionService.java |   6 +-
 .../connection/ModeledConnectionRecord.java     |  31 +-
 11 files changed, 632 insertions(+), 540 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java
new file mode 100644
index 0000000..86f2204
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.base;
+
+import java.util.Date;
+
+/**
+ * A single activity record representing an arbitrary activity performed by a
+ * user.
+ */
+public class ActivityRecordModel {
+
+    /**
+     * The database ID of the user associated with this activity record.
+     */
+    private Integer userID;
+
+    /**
+     * The username of the user that performed the activity.
+     */
+    private String username;
+
+    /**
+     * The remote host associated with the user that performed the activity.
+     */
+    private String remoteHost;
+
+    /**
+     * The time the activity was initiated by the associated user.
+     */
+    private Date startDate;
+
+    /**
+     * The time the activity ended, or null if the end time is not known or
+     * the activity is still in progress.
+     */
+    private Date endDate;
+
+    /**
+     * Returns the database ID of the user associated with this activity
+     * record.
+     * 
+     * @return
+     *     The database ID of the user associated with this activity record.
+     */
+    public Integer getUserID() {
+        return userID;
+    }
+
+    /**
+     * Sets the database ID of the user associated with this activity record.
+     *
+     * @param userID
+     *     The database ID of the user to associate with this activity
+     *     record.
+     */
+    public void setUserID(Integer userID) {
+        this.userID = userID;
+    }
+
+    /**
+     * Returns the username of the user that performed the activity associated
+     * with this record.
+     * 
+     * @return
+     *     The username of the user that performed the activity associated with
+     *     this record.
+     */
+    public String getUsername() {
+        return username;
+    }
+
+    /**
+     * Sets the username of the user that performed the activity associated
+     * with this record.
+     *
+     * @param username
+     *     The username of the user that performed the activity associated with
+     *     this record.
+     */
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    /**
+     * Returns the remote host associated with the user that performed the
+     * activity.
+     *
+     * @return
+     *     The remote host associated with the user that performed the activity.
+     */
+    public String getRemoteHost() {
+        return remoteHost;
+    }
+
+    /**
+     * Sets the remote host associated with the user that performed the
+     * activity.
+     *
+     * @param remoteHost
+     *     The remote host associated with the user that performed the activity.
+     */
+    public void setRemoteHost(String remoteHost) {
+        this.remoteHost = remoteHost;
+    }
+
+    /**
+     * Returns the time the activity was initiated by the associated user.
+     *
+     * @return
+     *     The time the activity was initiated by the associated user.
+     */
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    /**
+     * Sets the time the activity was initiated by the associated user.
+     *
+     * @param startDate
+     *     The time the activity was initiated by the associated user.
+     */
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
+
+    /**
+     * Returns the time the activity ended, or null if the end time is not
+     * known or the activity is still in progress.
+     *
+     * @return
+     *     The time the activity ended, or null if the end time is not known or
+     *     the activity is still in progress.
+     */
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    /**
+     * Sets the time the activity ended, if known.
+     *
+     * @param endDate
+     *     The time the activity ended, or null if the end time is not known or
+     *     the activity is still in progress.
+     */
+    public void setEndDate(Date endDate) {
+        this.endDate = endDate;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSearchTerm.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSearchTerm.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSearchTerm.java
new file mode 100644
index 0000000..54af1a6
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSearchTerm.java
@@ -0,0 +1,291 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.base;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A search term for querying historical records of arbitrary activities. This
+ * will contain a the search term in string form and, if that string appears to
+ * be a date. a corresponding date range.
+ */
+public class ActivityRecordSearchTerm {
+    
+    /**
+     * A pattern that can match a year, year and month, or year and month and
+     * day.
+     */
+    private static final Pattern DATE_PATTERN = 
+            Pattern.compile("(\\d+)(?:-(\\d+)?(?:-(\\d+)?)?)?");
+
+    /**
+     * The index of the group within <code>DATE_PATTERN</code> containing the
+     * year number.
+     */
+    private static final int YEAR_GROUP = 1;
+
+    /**
+     * The index of the group within <code>DATE_PATTERN</code> containing the
+     * month number, if any.
+     */
+    private static final int MONTH_GROUP = 2;
+
+    /**
+     * The index of the group within <code>DATE_PATTERN</code> containing the
+     * day number, if any.
+     */
+    private static final int DAY_GROUP = 3;
+
+    /**
+     * The start of the date range for records that should be retrieved, if the
+     * provided search term appears to be a date.
+     */
+    private final Date startDate;
+    
+    /**
+     * The end of the date range for records that should be retrieved, if the
+     * provided search term appears to be a date.
+     */
+    private final Date endDate;
+    
+    /**
+     * The string that should be searched for.
+     */
+    private final String term;
+    
+    /**
+     * Parse the given string as an integer, returning the provided default
+     * value if the string is null.
+     * 
+     * @param str
+     *     The string to parse as an integer.
+     *
+     * @param defaultValue
+     *     The value to return if <code>str</code> is null.
+     * 
+     * @return
+     *     The parsed value, or the provided default value if <code>str</code>
+     *     is null.
+     */
+    private static int parseInt(String str, int defaultValue) {
+        
+        if (str == null)
+            return defaultValue;
+        
+        return Integer.parseInt(str);
+
+    }
+    
+    /**
+     * Returns a new calendar representing the last millisecond of the same
+     * year as <code>calendar</code>.
+     * 
+     * @param calendar
+     *     The calendar defining the year whose end (last millisecond) is to be
+     *     returned.
+     *
+     * @return
+     *     A new calendar representing the last millisecond of the same year as
+     *     <code>calendar</code>.
+     */
+    private static Calendar getEndOfYear(Calendar calendar) {
+
+        // Get first day of next year
+        Calendar endOfYear = Calendar.getInstance();
+        endOfYear.clear();
+        endOfYear.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1);
+
+        // Transform into the last millisecond of the given year
+        endOfYear.add(Calendar.MILLISECOND, -1);
+
+        return endOfYear;
+
+    }
+    
+    /**
+     * Returns a new calendar representing the last millisecond of the same
+     * month and year as <code>calendar</code>.
+     * 
+     * @param calendar
+     *     The calendar defining the month and year whose end (last millisecond) 
+     *     is to be returned.
+     *
+     * @return
+     *     A new calendar representing the last millisecond of the same month 
+     *     and year as <code>calendar</code>.
+     */
+    private static Calendar getEndOfMonth(Calendar calendar) {
+
+        // Copy given calender only up to given month
+        Calendar endOfMonth = Calendar.getInstance();
+        endOfMonth.clear();
+        endOfMonth.set(Calendar.YEAR,  calendar.get(Calendar.YEAR));
+        endOfMonth.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
+
+        // Advance to the last millisecond of the given month
+        endOfMonth.add(Calendar.MONTH,        1);
+        endOfMonth.add(Calendar.MILLISECOND, -1);
+
+        return endOfMonth;
+
+    }
+    
+    /**
+     * Returns a new calendar representing the last millisecond of the same
+     * year, month, and day as <code>calendar</code>.
+     * 
+     * @param calendar
+     *     The calendar defining the year, month, and day whose end 
+     *     (last millisecond) is to be returned.
+     *
+     * @return
+     *     A new calendar representing the last millisecond of the same year, 
+     *     month, and day as <code>calendar</code>.
+     */
+    private static Calendar getEndOfDay(Calendar calendar) {
+
+        // Copy given calender only up to given month
+        Calendar endOfMonth = Calendar.getInstance();
+        endOfMonth.clear();
+        endOfMonth.set(Calendar.YEAR,         calendar.get(Calendar.YEAR));
+        endOfMonth.set(Calendar.MONTH,        calendar.get(Calendar.MONTH));
+        endOfMonth.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH));
+
+        // Advance to the last millisecond of the given day
+        endOfMonth.add(Calendar.DAY_OF_MONTH, 1);
+        endOfMonth.add(Calendar.MILLISECOND, -1);
+
+        return endOfMonth;
+
+    }
+
+    /**
+     * Creates a new ActivityRecordSearchTerm representing the given string.
+     * If the given string appears to be a date, the start and end dates of the
+     * implied date range will be automatically determined and made available
+     * via getStartDate() and getEndDate() respectively.
+     *
+     * @param term
+     *     The string that should be searched for.
+     */
+    public ActivityRecordSearchTerm(String term) {
+
+        // Search terms absolutely must not be null
+        if (term == null)
+            throw new NullPointerException("Search terms may not be null");
+
+        this.term = term;
+
+        // Parse start/end of date range if term appears to be a date
+        Matcher matcher = DATE_PATTERN.matcher(term);
+        if (matcher.matches()) {
+
+            // Retrieve date components from term
+            String year  = matcher.group(YEAR_GROUP);
+            String month = matcher.group(MONTH_GROUP);
+            String day   = matcher.group(DAY_GROUP);
+            
+            // Parse start date from term
+            Calendar startCalendar = Calendar.getInstance();
+            startCalendar.clear();
+            startCalendar.set(
+                Integer.parseInt(year),
+                parseInt(month, 1) - 1,
+                parseInt(day,   1)
+            );
+
+            Calendar endCalendar;
+
+            // Derive end date from start date
+            if (month == null) {
+                endCalendar = getEndOfYear(startCalendar);
+            }
+            else if (day == null) {
+                endCalendar = getEndOfMonth(startCalendar);
+            }
+            else {
+                endCalendar = getEndOfDay(startCalendar);
+            }
+
+            // Convert results back into dates
+            this.startDate = startCalendar.getTime();
+            this.endDate   = endCalendar.getTime();
+            
+        }
+
+        // The search term doesn't look like a date
+        else {
+            this.startDate = null;
+            this.endDate   = null;
+        }
+
+    }
+
+    /**
+     * Returns the start of the date range for records that should be retrieved, 
+     * if the provided search term appears to be a date.
+     * 
+     * @return
+     *     The start of the date range.
+     */
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    /**
+     * Returns the end of the date range for records that should be retrieved, 
+     * if the provided search term appears to be a date.
+     * 
+     * @return
+     *     The end of the date range.
+     */
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    /**
+     * Returns the string that should be searched for.
+     * 
+     * @return
+     *     The search term.
+     */
+    public String getTerm() {
+        return term;
+    }
+
+    @Override
+    public int hashCode() {
+        return term.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+
+        if (obj == null || !(obj instanceof ActivityRecordSearchTerm))
+            return false;
+
+        return ((ActivityRecordSearchTerm) obj).getTerm().equals(getTerm());
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSortPredicate.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSortPredicate.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSortPredicate.java
new file mode 100644
index 0000000..ab0d3ce
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSortPredicate.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.base;
+
+import org.apache.guacamole.net.auth.ActivityRecordSet;
+
+/**
+ * A sort predicate which species the property to use when sorting activity
+ * records, along with the sort order.
+ */
+public class ActivityRecordSortPredicate {
+
+    /**
+     * The property to use when sorting ActivityRecords.
+     */
+    private final ActivityRecordSet.SortableProperty property;
+
+    /**
+     * Whether the sort order is descending (true) or ascending (false).
+     */
+    private final boolean descending;
+    
+    /**
+     * Creates a new ActivityRecordSortPredicate with the given sort property
+     * and sort order.
+     * 
+     * @param property 
+     *     The property to use when sorting ActivityRecords.
+     * 
+     * @param descending 
+     *     Whether the sort order is descending (true) or ascending (false).
+     */
+    public ActivityRecordSortPredicate(ActivityRecordSet.SortableProperty property,
+            boolean descending) {
+        this.property   = property;
+        this.descending = descending;
+    }
+    
+    /**
+     * Returns the property that should be used when sorting ActivityRecords.
+     *
+     * @return
+     *     The property that should be used when sorting ActivityRecords.
+     */
+    public ActivityRecordSet.SortableProperty getProperty() {
+        return property;
+    }
+
+    /**
+     * Returns whether the sort order is descending.
+     *
+     * @return
+     *     true if the sort order is descending, false if the sort order is
+     *     ascending.
+     */
+    public boolean isDescending() {
+        return descending;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecord.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecord.java
new file mode 100644
index 0000000..95b1a25
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecord.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.base;
+
+
+import java.util.Date;
+import org.apache.guacamole.net.auth.ActivityRecord;
+
+/**
+ * An ActivityRecord which is backed by a database model.
+ */
+public class ModeledActivityRecord implements ActivityRecord {
+
+    /**
+     * The model object backing this activity record.
+     */
+    private final ActivityRecordModel model;
+
+    /**
+     * Creates a new ModeledActivityRecord backed by the given model object.
+     * Changes to this record will affect the backing model object, and changes
+     * to the backing model object will affect this record.
+     * 
+     * @param model
+     *     The model object to use to back this activity record.
+     */
+    public ModeledActivityRecord(ActivityRecordModel model) {
+        this.model = model;
+    }
+
+    @Override
+    public Date getStartDate() {
+        return model.getStartDate();
+    }
+
+    @Override
+    public Date getEndDate() {
+        return model.getEndDate();
+    }
+
+    @Override
+    public String getRemoteHost() {
+        return model.getRemoteHost();
+    }
+
+    @Override
+    public String getUsername() {
+        return model.getUsername();
+    }
+
+    @Override
+    public boolean isActive() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
index aefff92..637fd0f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
@@ -21,6 +21,8 @@ package org.apache.guacamole.auth.jdbc.connection;
 
 import java.util.Collection;
 import java.util.List;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
 import org.apache.ibatis.annotations.Param;
 import org.apache.guacamole.auth.jdbc.user.UserModel;
 
@@ -75,8 +77,8 @@ public interface ConnectionRecordMapper {
      * @return
      *     The results of the search performed with the given parameters.
      */
-    List<ConnectionRecordModel> search(@Param("terms") Collection<ConnectionRecordSearchTerm> terms,
-            @Param("sortPredicates") List<ConnectionRecordSortPredicate> sortPredicates,
+    List<ConnectionRecordModel> search(@Param("terms") Collection<ActivityRecordSearchTerm> terms,
+            @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
             @Param("limit") int limit);
 
     /**
@@ -104,8 +106,8 @@ public interface ConnectionRecordMapper {
      *     The results of the search performed with the given parameters.
      */
     List<ConnectionRecordModel> searchReadable(@Param("user") UserModel user,
-            @Param("terms") Collection<ConnectionRecordSearchTerm> terms,
-            @Param("sortPredicates") List<ConnectionRecordSortPredicate> sortPredicates,
+            @Param("terms") Collection<ActivityRecordSearchTerm> terms,
+            @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
             @Param("limit") int limit);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordModel.java
index f142f4e..29c5556 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordModel.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordModel.java
@@ -19,14 +19,14 @@
 
 package org.apache.guacamole.auth.jdbc.connection;
 
-import java.util.Date;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
 
 /**
  * A single connection record representing a past usage of a particular
  * connection. If the connection was being shared, the sharing profile used to
  * join the connection is included in the record.
  */
-public class ConnectionRecordModel {
+public class ConnectionRecordModel extends ActivityRecordModel {
 
     /**
      * The identifier of the connection associated with this connection record.
@@ -54,32 +54,6 @@ public class ConnectionRecordModel {
     private String sharingProfileName;
 
     /**
-     * The database ID of the user associated with this connection record.
-     */
-    private Integer userID;
-
-    /**
-     * The username of the user associated with this connection record.
-     */
-    private String username;
-
-    /**
-     * The remote host associated with this connection record.
-     */
-    private String remoteHost;
-
-    /**
-     * The time the connection was initiated by the associated user.
-     */
-    private Date startDate;
-
-    /**
-     * The time the connection ended, or null if the end time is not known or
-     * the connection is still running.
-     */
-    private Date endDate;
-
-    /**
      * Returns the identifier of the connection associated with this connection
      * record.
      *
@@ -179,109 +153,4 @@ public class ConnectionRecordModel {
         this.sharingProfileName = sharingProfileName;
     }
 
-    /**
-     * Returns the database ID of the user associated with this connection
-     * record.
-     * 
-     * @return
-     *     The database ID of the user associated with this connection record.
-     */
-    public Integer getUserID() {
-        return userID;
-    }
-
-    /**
-     * Sets the database ID of the user associated with this connection record.
-     *
-     * @param userID
-     *     The database ID of the user to associate with this connection
-     *     record.
-     */
-    public void setUserID(Integer userID) {
-        this.userID = userID;
-    }
-
-    /**
-     * Returns the username of the user associated with this connection record.
-     * 
-     * @return
-     *     The username of the user associated with this connection record.
-     */
-    public String getUsername() {
-        return username;
-    }
-
-    /**
-     * Sets the username of the user associated with this connection record.
-     *
-     * @param username
-     *     The username of the user to associate with this connection record.
-     */
-    public void setUsername(String username) {
-        this.username = username;
-    }
-
-    /**
-     * Returns the remote host associated with this connection record.
-     *
-     * @return
-     *     The remote host associated with this connection record.
-     */
-    public String getRemoteHost() {
-        return remoteHost;
-    }
-
-    /**
-     * Sets the remote host associated with this connection record.
-     *
-     * @param remoteHost
-     *     The remote host to associate with this connection record.
-     */
-    public void setRemoteHost(String remoteHost) {
-        this.remoteHost = remoteHost;
-    }
-
-    /**
-     * Returns the date that the associated connection was established.
-     *
-     * @return
-     *     The date the associated connection was established.
-     */
-    public Date getStartDate() {
-        return startDate;
-    }
-
-    /**
-     * Sets the date that the associated connection was established.
-     *
-     * @param startDate
-     *     The date that the associated connection was established.
-     */
-    public void setStartDate(Date startDate) {
-        this.startDate = startDate;
-    }
-
-    /**
-     * Returns the date that the associated connection ended, or null if no
-     * end date was recorded. The lack of an end date does not necessarily
-     * mean that the connection is still active.
-     *
-     * @return
-     *     The date the associated connection ended, or null if no end date was
-     *     recorded.
-     */
-    public Date getEndDate() {
-        return endDate;
-    }
-
-    /**
-     * Sets the date that the associated connection ended.
-     *
-     * @param endDate
-     *     The date that the associated connection ended.
-     */
-    public void setEndDate(Date endDate) {
-        this.endDate = endDate;
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSearchTerm.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSearchTerm.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSearchTerm.java
deleted file mode 100644
index 844eff7..0000000
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSearchTerm.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.guacamole.auth.jdbc.connection;
-
-import java.util.Calendar;
-import java.util.Date;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A search term for querying historical connection records. This will contain
- * a the search term in string form and, if that string appears to be a date. a
- * corresponding date range.
- */
-public class ConnectionRecordSearchTerm {
-    
-    /**
-     * A pattern that can match a year, year and month, or year and month and
-     * day.
-     */
-    private static final Pattern DATE_PATTERN = 
-            Pattern.compile("(\\d+)(?:-(\\d+)?(?:-(\\d+)?)?)?");
-
-    /**
-     * The index of the group within <code>DATE_PATTERN</code> containing the
-     * year number.
-     */
-    private static final int YEAR_GROUP = 1;
-
-    /**
-     * The index of the group within <code>DATE_PATTERN</code> containing the
-     * month number, if any.
-     */
-    private static final int MONTH_GROUP = 2;
-
-    /**
-     * The index of the group within <code>DATE_PATTERN</code> containing the
-     * day number, if any.
-     */
-    private static final int DAY_GROUP = 3;
-
-    /**
-     * The start of the date range for records that should be retrieved, if the
-     * provided search term appears to be a date.
-     */
-    private final Date startDate;
-    
-    /**
-     * The end of the date range for records that should be retrieved, if the
-     * provided search term appears to be a date.
-     */
-    private final Date endDate;
-    
-    /**
-     * The string that should be searched for.
-     */
-    private final String term;
-    
-    /**
-     * Parse the given string as an integer, returning the provided default
-     * value if the string is null.
-     * 
-     * @param str
-     *     The string to parse as an integer.
-     *
-     * @param defaultValue
-     *     The value to return if <code>str</code> is null.
-     * 
-     * @return
-     *     The parsed value, or the provided default value if <code>str</code>
-     *     is null.
-     */
-    private static int parseInt(String str, int defaultValue) {
-        
-        if (str == null)
-            return defaultValue;
-        
-        return Integer.parseInt(str);
-
-    }
-    
-    /**
-     * Returns a new calendar representing the last millisecond of the same
-     * year as <code>calendar</code>.
-     * 
-     * @param calendar
-     *     The calendar defining the year whose end (last millisecond) is to be
-     *     returned.
-     *
-     * @return
-     *     A new calendar representing the last millisecond of the same year as
-     *     <code>calendar</code>.
-     */
-    private static Calendar getEndOfYear(Calendar calendar) {
-
-        // Get first day of next year
-        Calendar endOfYear = Calendar.getInstance();
-        endOfYear.clear();
-        endOfYear.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1);
-
-        // Transform into the last millisecond of the given year
-        endOfYear.add(Calendar.MILLISECOND, -1);
-
-        return endOfYear;
-
-    }
-    
-    /**
-     * Returns a new calendar representing the last millisecond of the same
-     * month and year as <code>calendar</code>.
-     * 
-     * @param calendar
-     *     The calendar defining the month and year whose end (last millisecond) 
-     *     is to be returned.
-     *
-     * @return
-     *     A new calendar representing the last millisecond of the same month 
-     *     and year as <code>calendar</code>.
-     */
-    private static Calendar getEndOfMonth(Calendar calendar) {
-
-        // Copy given calender only up to given month
-        Calendar endOfMonth = Calendar.getInstance();
-        endOfMonth.clear();
-        endOfMonth.set(Calendar.YEAR,  calendar.get(Calendar.YEAR));
-        endOfMonth.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
-
-        // Advance to the last millisecond of the given month
-        endOfMonth.add(Calendar.MONTH,        1);
-        endOfMonth.add(Calendar.MILLISECOND, -1);
-
-        return endOfMonth;
-
-    }
-    
-    /**
-     * Returns a new calendar representing the last millisecond of the same
-     * year, month, and day as <code>calendar</code>.
-     * 
-     * @param calendar
-     *     The calendar defining the year, month, and day whose end 
-     *     (last millisecond) is to be returned.
-     *
-     * @return
-     *     A new calendar representing the last millisecond of the same year, 
-     *     month, and day as <code>calendar</code>.
-     */
-    private static Calendar getEndOfDay(Calendar calendar) {
-
-        // Copy given calender only up to given month
-        Calendar endOfMonth = Calendar.getInstance();
-        endOfMonth.clear();
-        endOfMonth.set(Calendar.YEAR,         calendar.get(Calendar.YEAR));
-        endOfMonth.set(Calendar.MONTH,        calendar.get(Calendar.MONTH));
-        endOfMonth.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH));
-
-        // Advance to the last millisecond of the given day
-        endOfMonth.add(Calendar.DAY_OF_MONTH, 1);
-        endOfMonth.add(Calendar.MILLISECOND, -1);
-
-        return endOfMonth;
-
-    }
-
-    /**
-     * Creates a new ConnectionRecordSearchTerm representing the given string.
-     * If the given string appears to be a date, the start and end dates of the
-     * implied date range will be automatically determined and made available
-     * via getStartDate() and getEndDate() respectively.
-     *
-     * @param term
-     *     The string that should be searched for.
-     */
-    public ConnectionRecordSearchTerm(String term) {
-
-        // Search terms absolutely must not be null
-        if (term == null)
-            throw new NullPointerException("Search terms may not be null");
-
-        this.term = term;
-
-        // Parse start/end of date range if term appears to be a date
-        Matcher matcher = DATE_PATTERN.matcher(term);
-        if (matcher.matches()) {
-
-            // Retrieve date components from term
-            String year  = matcher.group(YEAR_GROUP);
-            String month = matcher.group(MONTH_GROUP);
-            String day   = matcher.group(DAY_GROUP);
-            
-            // Parse start date from term
-            Calendar startCalendar = Calendar.getInstance();
-            startCalendar.clear();
-            startCalendar.set(
-                Integer.parseInt(year),
-                parseInt(month, 1) - 1,
-                parseInt(day,   1)
-            );
-
-            Calendar endCalendar;
-
-            // Derive end date from start date
-            if (month == null) {
-                endCalendar = getEndOfYear(startCalendar);
-            }
-            else if (day == null) {
-                endCalendar = getEndOfMonth(startCalendar);
-            }
-            else {
-                endCalendar = getEndOfDay(startCalendar);
-            }
-
-            // Convert results back into dates
-            this.startDate = startCalendar.getTime();
-            this.endDate   = endCalendar.getTime();
-            
-        }
-
-        // The search term doesn't look like a date
-        else {
-            this.startDate = null;
-            this.endDate   = null;
-        }
-
-    }
-
-    /**
-     * Returns the start of the date range for records that should be retrieved, 
-     * if the provided search term appears to be a date.
-     * 
-     * @return
-     *     The start of the date range.
-     */
-    public Date getStartDate() {
-        return startDate;
-    }
-
-    /**
-     * Returns the end of the date range for records that should be retrieved, 
-     * if the provided search term appears to be a date.
-     * 
-     * @return
-     *     The end of the date range.
-     */
-    public Date getEndDate() {
-        return endDate;
-    }
-
-    /**
-     * Returns the string that should be searched for.
-     * 
-     * @return
-     *     The search term.
-     */
-    public String getTerm() {
-        return term;
-    }
-
-    @Override
-    public int hashCode() {
-        return term.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-
-        if (obj == null || !(obj instanceof ConnectionRecordSearchTerm))
-            return false;
-
-        return ((ConnectionRecordSearchTerm) obj).getTerm().equals(getTerm());
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
index 7b3d629..df2a0a9 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
@@ -26,6 +26,8 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
 import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
 import org.apache.guacamole.net.auth.ActivityRecordSet;
 import org.apache.guacamole.net.auth.ActivityRecordSet.SortableProperty;
@@ -52,8 +54,8 @@ public class ConnectionRecordSet extends RestrictedObject
      * connection record not matching each of the strings within the collection 
      * will be excluded from the results.
      */
-    private final Set<ConnectionRecordSearchTerm> requiredContents = 
-            new HashSet<ConnectionRecordSearchTerm>();
+    private final Set<ActivityRecordSearchTerm> requiredContents =
+            new HashSet<ActivityRecordSearchTerm>();
     
     /**
      * The maximum number of connection history records that should be returned
@@ -66,8 +68,8 @@ public class ConnectionRecordSet extends RestrictedObject
      * records, describing the properties involved and the sort order for those 
      * properties.
      */
-    private final List<ConnectionRecordSortPredicate> connectionRecordSortPredicates =
-            new ArrayList<ConnectionRecordSortPredicate>();
+    private final List<ActivityRecordSortPredicate> connectionRecordSortPredicates =
+            new ArrayList<ActivityRecordSortPredicate>();
     
     @Override
     public Collection<ConnectionRecord> asCollection()
@@ -79,7 +81,7 @@ public class ConnectionRecordSet extends RestrictedObject
     @Override
     public ConnectionRecordSet contains(String value)
             throws GuacamoleException {
-        requiredContents.add(new ConnectionRecordSearchTerm(value));
+        requiredContents.add(new ActivityRecordSearchTerm(value));
         return this;
     }
 
@@ -93,7 +95,7 @@ public class ConnectionRecordSet extends RestrictedObject
     public ConnectionRecordSet sort(SortableProperty property, boolean desc)
             throws GuacamoleException {
         
-        connectionRecordSortPredicates.add(new ConnectionRecordSortPredicate(
+        connectionRecordSortPredicates.add(new ActivityRecordSortPredicate(
             property,
             desc
         ));

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSortPredicate.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSortPredicate.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSortPredicate.java
deleted file mode 100644
index 69eee78..0000000
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSortPredicate.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.guacamole.auth.jdbc.connection;
-
-import org.apache.guacamole.net.auth.ActivityRecordSet;
-
-/**
- * A sort predicate which species the property to use when sorting connection
- * records, along with the sort order.
- */
-public class ConnectionRecordSortPredicate {
-
-    /**
-     * The property to use when sorting ConnectionRecords.
-     */
-    private final ActivityRecordSet.SortableProperty property;
-
-    /**
-     * Whether the sort order is descending (true) or ascending (false).
-     */
-    private final boolean descending;
-    
-    /**
-     * Creates a new ConnectionRecordSortPredicate with the given sort property 
-     * and sort order.
-     * 
-     * @param property 
-     *     The property to use when sorting ConnectionRecords.
-     * 
-     * @param descending 
-     *     Whether the sort order is descending (true) or ascending (false).
-     */
-    public ConnectionRecordSortPredicate(ActivityRecordSet.SortableProperty property,
-            boolean descending) {
-        this.property   = property;
-        this.descending = descending;
-    }
-    
-    /**
-     * Returns the property that should be used when sorting ConnectionRecords.
-     *
-     * @return
-     *     The property that should be used when sorting ConnectionRecords.
-     */
-    public ActivityRecordSet.SortableProperty getProperty() {
-        return property;
-    }
-
-    /**
-     * Returns whether the sort order is descending.
-     *
-     * @return
-     *     true if the sort order is descending, false if the sort order is
-     *     ascending.
-     */
-    public boolean isDescending() {
-        return descending;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
index f256324..983f395 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
@@ -34,6 +34,8 @@ import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
 import org.apache.guacamole.GuacamoleClientException;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
 import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObjectService;
 import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionMapper;
 import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
@@ -460,8 +462,8 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
      *     If permission to read the connection history is denied.
      */
     public List<ConnectionRecord> retrieveHistory(ModeledAuthenticatedUser user,
-            Collection<ConnectionRecordSearchTerm> requiredContents,
-            List<ConnectionRecordSortPredicate> sortPredicates, int limit)
+            Collection<ActivityRecordSearchTerm> requiredContents,
+            List<ActivityRecordSortPredicate> sortPredicates, int limit)
             throws GuacamoleException {
 
         List<ConnectionRecordModel> searchResults;

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java
index a5e83d4..9f34385 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java
@@ -20,13 +20,14 @@
 package org.apache.guacamole.auth.jdbc.connection;
 
 
-import java.util.Date;
+import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord;
 import org.apache.guacamole.net.auth.ConnectionRecord;
 
 /**
  * A ConnectionRecord which is backed by a database model.
  */
-public class ModeledConnectionRecord implements ConnectionRecord {
+public class ModeledConnectionRecord extends ModeledActivityRecord
+        implements ConnectionRecord {
 
     /**
      * The model object backing this connection record.
@@ -42,6 +43,7 @@ public class ModeledConnectionRecord implements ConnectionRecord {
      *     The model object to use to back this connection record.
      */
     public ModeledConnectionRecord(ConnectionRecordModel model) {
+        super(model);
         this.model = model;
     }
 
@@ -65,29 +67,4 @@ public class ModeledConnectionRecord implements ConnectionRecord {
         return model.getSharingProfileName();
     }
 
-    @Override
-    public Date getStartDate() {
-        return model.getStartDate();
-    }
-
-    @Override
-    public Date getEndDate() {
-        return model.getEndDate();
-    }
-
-    @Override
-    public String getRemoteHost() {
-        return model.getRemoteHost();
-    }
-
-    @Override
-    public String getUsername() {
-        return model.getUsername();
-    }
-
-    @Override
-    public boolean isActive() {
-        return false;
-    }
-
 }


[13/16] guacamole-client git commit: GUACAMOLE-394: Automatically update the end time of user history records upon logout.

Posted by vn...@apache.org.
GUACAMOLE-394: Automatically update the end time of user history records upon logout.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/28e7d215
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/28e7d215
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/28e7d215

Branch: refs/heads/staging/0.9.14
Commit: 28e7d215aceb2e5c572bdfc00207ef37d33ca8e8
Parents: 3ccb4d4
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 18:03:22 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../auth/jdbc/base/ActivityRecordModel.java     | 26 ++++++++++++++++++++
 .../auth/jdbc/user/ModeledUserContext.java      |  6 ++++-
 .../auth/jdbc/user/UserRecordMapper.java        | 11 +++++++++
 .../auth/jdbc/user/UserRecordMapper.xml         | 16 +++++++++++-
 .../auth/jdbc/user/UserRecordMapper.xml         | 16 +++++++++++-
 .../auth/jdbc/user/UserRecordMapper.xml         | 16 +++++++++++-
 6 files changed, 87 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/28e7d215/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java
index 86f2204..fbf6209 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java
@@ -28,6 +28,11 @@ import java.util.Date;
 public class ActivityRecordModel {
 
     /**
+     * The ID of this object in the database, if any.
+     */
+    private Integer recordID;
+
+    /**
      * The database ID of the user associated with this activity record.
      */
     private Integer userID;
@@ -54,6 +59,27 @@ public class ActivityRecordModel {
     private Date endDate;
 
     /**
+     * Returns the ID of this record in the database, if it exists.
+     *
+     * @return
+     *     The ID of this record in the database, or null if this record was
+     *     not retrieved from the database.
+     */
+    public Integer getRecordID() {
+        return recordID;
+    }
+
+    /**
+     * Sets the database ID of this record to the given value.
+     *
+     * @param recordID
+     *     The ID to assign to this object.
+     */
+    public void setRecordID(Integer recordID) {
+        this.recordID = recordID;
+    }
+
+    /**
      * Returns the database ID of the user associated with this activity
      * record.
      * 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/28e7d215/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
index 0b3b121..5bfcda6 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
@@ -231,7 +231,11 @@ public class ModeledUserContext extends RestrictedObject
 
     @Override
     public void invalidate() {
-        // Nothing to invalidate
+
+        // Record logout time
+        userRecord.setEndDate(new Date());
+        userRecordMapper.update(userRecord);
+
     }
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/28e7d215/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
index 68f0c94..b2177bf 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
@@ -57,6 +57,17 @@ public interface UserRecordMapper {
     int insert(@Param("record") ActivityRecordModel record);
 
     /**
+     * Updates the given user login record.
+     *
+     * @param record
+     *     The user login record to update.
+     *
+     * @return
+     *     The number of rows updated.
+     */
+    int update(@Param("record") ActivityRecordModel record);
+
+    /**
      * Searches for up to <code>limit</code> user login records that contain
      * the given terms, sorted by the given predicates, regardless of whether
      * the data they are associated with is is readable by any particular user.

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/28e7d215/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
index 0467452..bbae03b 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -25,6 +25,7 @@
 
     <!-- Result mapper for system permissions -->
     <resultMap id="UserRecordResultMap" type="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+        <id     column="history_id"  property="recordID"   jdbcType="INTEGER"/>
         <result column="remote_host" property="remoteHost" jdbcType="VARCHAR"/>
         <result column="user_id"     property="userID"     jdbcType="INTEGER"/>
         <result column="username"    property="username"   jdbcType="VARCHAR"/>
@@ -52,7 +53,8 @@
     </select>
 
     <!-- Insert the given user record -->
-    <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+    <insert id="insert" useGeneratedKeys="true" keyProperty="record.recordID"
+            parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
 
         INSERT INTO guacamole_user_history (
             remote_host,
@@ -72,6 +74,18 @@
 
     </insert>
 
+    <!-- Update the given user record -->
+    <update id="update" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+        UPDATE guacamole_user_history
+        SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
+            user_id     = (SELECT user_id FROM guacamole_user
+                           WHERE username = #{record.username,jdbcType=VARCHAR}),
+            username    = #{record.username,jdbcType=VARCHAR},
+            start_date  = #{record.startDate,jdbcType=TIMESTAMP},
+            end_date    = #{record.endDate,jdbcType=TIMESTAMP}
+        WHERE history_id = #{record.recordID,jdbcType=INTEGER}
+    </update>
+
     <!-- Search for specific user records -->
     <select id="search" resultMap="UserRecordResultMap">
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/28e7d215/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
index 0467452..014b38a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -25,6 +25,7 @@
 
     <!-- Result mapper for system permissions -->
     <resultMap id="UserRecordResultMap" type="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+        <id     column="history_id"  property="recordID"   jdbcType="INTEGER"/>
         <result column="remote_host" property="remoteHost" jdbcType="VARCHAR"/>
         <result column="user_id"     property="userID"     jdbcType="INTEGER"/>
         <result column="username"    property="username"   jdbcType="VARCHAR"/>
@@ -52,7 +53,8 @@
     </select>
 
     <!-- Insert the given user record -->
-    <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+    <insert id="insert" useGeneratedKeys="true" keyProperty="record.recordID"
+            parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
 
         INSERT INTO guacamole_user_history (
             remote_host,
@@ -72,6 +74,18 @@
 
     </insert>
 
+    <!-- Update the given user record -->
+    <update id="update" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+        UPDATE guacamole_user_history
+        SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
+            user_id     = (SELECT user_id FROM guacamole_user
+                           WHERE username = #{record.username,jdbcType=VARCHAR}),
+            username    = #{record.username,jdbcType=VARCHAR},
+            start_date  = #{record.startDate,jdbcType=TIMESTAMP},
+            end_date    = #{record.endDate,jdbcType=TIMESTAMP}
+        WHERE history_id = #{record.recordID,jdbcType=INTEGER}::integer
+    </update>
+
     <!-- Search for specific user records -->
     <select id="search" resultMap="UserRecordResultMap">
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/28e7d215/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
index fafa863..0143dda 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -25,6 +25,7 @@
 
     <!-- Result mapper for system permissions -->
     <resultMap id="UserRecordResultMap" type="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+        <id     column="history_id"  property="recordID"   jdbcType="INTEGER"/>
         <result column="remote_host" property="remoteHost" jdbcType="VARCHAR"/>
         <result column="user_id"     property="userID"     jdbcType="INTEGER"/>
         <result column="username"    property="username"   jdbcType="VARCHAR"/>
@@ -52,7 +53,8 @@
     </select>
 
     <!-- Insert the given user record -->
-    <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+    <insert id="insert" useGeneratedKeys="true" keyProperty="record.recordID"
+            parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
 
         INSERT INTO [guacamole_user_history] (
             remote_host,
@@ -72,6 +74,18 @@
 
     </insert>
 
+    <!-- Update the given user record -->
+    <update id="update" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
+        UPDATE [guacamole_user_history]
+        SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
+            user_id     = (SELECT user_id FROM [guacamole_user]
+                           WHERE username = #{record.username,jdbcType=VARCHAR}),
+            username    = #{record.username,jdbcType=VARCHAR},
+            start_date  = #{record.startDate,jdbcType=TIMESTAMP},
+            end_date    = #{record.endDate,jdbcType=TIMESTAMP}
+        WHERE history_id = #{record.recordID,jdbcType=INTEGER}
+    </update>
+
     <!-- Search for specific user records -->
     <select id="search" resultMap="UserRecordResultMap">
 


[12/16] guacamole-client git commit: GUACAMOLE-394: Implement full retrieval of user login history.

Posted by vn...@apache.org.
GUACAMOLE-394: Implement full retrieval of user login history.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/7e8accab
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/7e8accab
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/7e8accab

Branch: refs/heads/staging/0.9.14
Commit: 7e8accab62a2ea2be89cc24de5a152c7147c983e
Parents: 2414c9a
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 14:21:32 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../guacamole/auth/jdbc/user/ModeledUser.java   |   8 +-
 .../auth/jdbc/user/ModeledUserContext.java      |  10 +-
 .../guacamole/auth/jdbc/user/UserRecordSet.java |  59 ++++++++
 .../guacamole/auth/jdbc/user/UserService.java   | 133 ++++++++++++++++++-
 4 files changed, 207 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/7e8accab/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
index b039a4e..5ffc458 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
@@ -145,6 +145,12 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
     ));
 
     /**
+     * Service for managing users.
+     */
+    @Inject
+    private UserService userService;
+
+    /**
      * Service for hashing passwords.
      */
     @Inject
@@ -801,7 +807,7 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
 
     @Override
     public List<ActivityRecord> getHistory() throws GuacamoleException {
-        return Collections.<ActivityRecord>emptyList();
+        return userService.retrieveHistory(getCurrentUser(), this);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/7e8accab/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
index 1b238ab..fc2c972 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
@@ -99,6 +99,12 @@ public class ModeledUserContext extends RestrictedObject
      */
     @Inject
     private Provider<ConnectionRecordSet> connectionRecordSetProvider;
+
+    /**
+     * Provider for creating user record sets.
+     */
+    @Inject
+    private Provider<UserRecordSet> userRecordSetProvider;
     
     @Override
     public void init(ModeledAuthenticatedUser currentUser) {
@@ -167,7 +173,9 @@ public class ModeledUserContext extends RestrictedObject
     @Override
     public ActivityRecordSet<ActivityRecord> getUserHistory()
             throws GuacamoleException {
-        return new SimpleActivityRecordSet<ActivityRecord>();
+        UserRecordSet userRecordSet = userRecordSetProvider.get();
+        userRecordSet.init(getCurrentUser());
+        return userRecordSet;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/7e8accab/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordSet.java
new file mode 100644
index 0000000..c1b4897
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordSet.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.user;
+
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
+import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecordSet;
+import org.apache.guacamole.net.auth.ActivityRecord;
+import org.apache.guacamole.net.auth.AuthenticatedUser;
+
+/**
+ * A JDBC implementation of ActivityRecordSet for retrieving user login history.
+ * Calls to asCollection() will query user login records from the database.
+ * Which records are returned will be determined by the values passed in
+ * earlier.
+ */
+public class UserRecordSet extends ModeledActivityRecordSet<ActivityRecord> {
+
+    /**
+     * Service for managing user objects.
+     */
+    @Inject
+    private UserService userService;
+    
+    @Override
+    protected Collection<ActivityRecord> retrieveHistory(
+            AuthenticatedUser user, Set<ActivityRecordSearchTerm> requiredContents,
+            List<ActivityRecordSortPredicate> sortPredicates, int limit)
+            throws GuacamoleException {
+
+        // Retrieve history from database
+        return userService.retrieveHistory(getCurrentUser(),
+                requiredContents, sortPredicates, limit);
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/7e8accab/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
index 3dc025f..090963f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
@@ -21,16 +21,24 @@ package org.apache.guacamole.auth.jdbc.user;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import javax.servlet.http.HttpServletRequest;
 import org.apache.guacamole.net.auth.Credentials;
 import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
 import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectService;
 import org.apache.guacamole.GuacamoleClientException;
 import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleSecurityException;
 import org.apache.guacamole.GuacamoleUnsupportedException;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
+import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord;
+import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordModel;
 import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
 import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel;
 import org.apache.guacamole.auth.jdbc.permission.UserPermissionMapper;
@@ -38,8 +46,10 @@ import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService;
 import org.apache.guacamole.auth.jdbc.security.PasswordPolicyService;
 import org.apache.guacamole.form.Field;
 import org.apache.guacamole.form.PasswordField;
+import org.apache.guacamole.net.auth.ActivityRecord;
 import org.apache.guacamole.net.auth.AuthenticatedUser;
 import org.apache.guacamole.net.auth.AuthenticationProvider;
+import org.apache.guacamole.net.auth.ConnectionRecord;
 import org.apache.guacamole.net.auth.User;
 import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
 import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
@@ -116,7 +126,13 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
      */
     @Inject
     private UserPermissionMapper userPermissionMapper;
-    
+
+    /**
+     * Mapper for accessing user login history.
+     */
+    @Inject
+    private UserRecordMapper userRecordMapper;
+
     /**
      * Provider for creating users.
      */
@@ -460,4 +476,119 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
 
     }
 
+    /**
+     * Returns a ActivityRecord object which is backed by the given model.
+     *
+     * @param model
+     *     The model object to use to back the returned connection record
+     *     object.
+     *
+     * @return
+     *     A connection record object which is backed by the given model.
+     */
+    protected ActivityRecord getObjectInstance(ActivityRecordModel model) {
+        return new ModeledActivityRecord(model);
+    }
+
+    /**
+     * Returns a list of ActivityRecord objects which are backed by the
+     * models in the given list.
+     *
+     * @param models
+     *     The model objects to use to back the activity record objects
+     *     within the returned list.
+     *
+     * @return
+     *     A list of activity record objects which are backed by the models
+     *     in the given list.
+     */
+    protected List<ActivityRecord> getObjectInstances(List<ActivityRecordModel> models) {
+
+        // Create new list of records by manually converting each model
+        List<ActivityRecord> objects = new ArrayList<ActivityRecord>(models.size());
+        for (ActivityRecordModel model : models)
+            objects.add(getObjectInstance(model));
+
+        return objects;
+
+    }
+
+    /**
+     * Retrieves the login history of the given user, including any active
+     * sessions.
+     *
+     * @param authenticatedUser
+     *     The user retrieving the login history.
+     *
+     * @param user
+     *     The user whose history is being retrieved.
+     *
+     * @return
+     *     The login history of the given user, including any active sessions.
+     *
+     * @throws GuacamoleException
+     *     If permission to read the login history is denied.
+     */
+    public List<ActivityRecord> retrieveHistory(ModeledAuthenticatedUser authenticatedUser,
+            ModeledUser user) throws GuacamoleException {
+
+        String username = user.getIdentifier();
+
+        // Retrieve history only if READ permission is granted
+        if (hasObjectPermission(authenticatedUser, username, ObjectPermission.Type.READ))
+            return getObjectInstances(userRecordMapper.select(username));
+
+        // The user does not have permission to read the history
+        throw new GuacamoleSecurityException("Permission denied.");
+
+    }
+
+    /**
+     * Retrieves user login history records matching the given criteria.
+     * Retrieves up to <code>limit</code> user history records matching the
+     * given terms and sorted by the given predicates. Only history records
+     * associated with data that the given user can read are returned.
+     *
+     * @param user
+     *     The user retrieving the login history.
+     *
+     * @param requiredContents
+     *     The search terms that must be contained somewhere within each of the
+     *     returned records.
+     *
+     * @param sortPredicates
+     *     A list of predicates to sort the returned records by, in order of
+     *     priority.
+     *
+     * @param limit
+     *     The maximum number of records that should be returned.
+     *
+     * @return
+     *     The login history of the given user, including any active sessions.
+     *
+     * @throws GuacamoleException
+     *     If permission to read the user login history is denied.
+     */
+    public List<ActivityRecord> retrieveHistory(ModeledAuthenticatedUser user,
+            Collection<ActivityRecordSearchTerm> requiredContents,
+            List<ActivityRecordSortPredicate> sortPredicates, int limit)
+            throws GuacamoleException {
+
+        List<ActivityRecordModel> searchResults;
+
+        // Bypass permission checks if the user is a system admin
+        if (user.getUser().isAdministrator())
+            searchResults = userRecordMapper.search(requiredContents,
+                    sortPredicates, limit);
+
+        // Otherwise only return explicitly readable history records
+        else
+            searchResults = userRecordMapper.searchReadable(user.getUser().getModel(),
+                    requiredContents, sortPredicates, limit);
+
+        return getObjectInstances(searchResults);
+
+    }
+
+
 }


[11/16] guacamole-client git commit: GUACAMOLE-394: Separate core of ConnectionRecordSet into ModeledActivityRecordSet.

Posted by vn...@apache.org.
GUACAMOLE-394: Separate core of ConnectionRecordSet into ModeledActivityRecordSet.

Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/2414c9a2
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/2414c9a2
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/2414c9a2

Branch: refs/heads/staging/0.9.14
Commit: 2414c9a2457ae57cf3df30f1d40535d1895525fb
Parents: adf016a
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 13:56:58 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../jdbc/base/ModeledActivityRecordSet.java     | 132 +++++++++++++++++++
 .../jdbc/connection/ConnectionRecordSet.java    |  67 ++--------
 2 files changed, 141 insertions(+), 58 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/2414c9a2/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecordSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecordSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecordSet.java
new file mode 100644
index 0000000..d259018
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecordSet.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.base;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.ActivityRecord;
+import org.apache.guacamole.net.auth.ActivityRecordSet;
+import org.apache.guacamole.net.auth.ActivityRecordSet.SortableProperty;
+import org.apache.guacamole.net.auth.AuthenticatedUser;
+
+/**
+ * A JDBC implementation of ActivityRecordSet. Calls to asCollection() will
+ * query history records using an implementation-specific mechanism. Which
+ * records are returned will be determined by the values passed in earlier.
+ *
+ * @param <RecordType>
+ *     The type of ActivityRecord contained within this set.
+ */
+public abstract class ModeledActivityRecordSet<RecordType extends ActivityRecord>
+        extends RestrictedObject implements ActivityRecordSet<RecordType> {
+
+    /**
+     * The set of strings that each must occur somewhere within the returned 
+     * records, whether within the associated username, an associated date, or
+     * other related data. If non-empty, any record not matching each of the
+     * strings within the collection will be excluded from the results.
+     */
+    private final Set<ActivityRecordSearchTerm> requiredContents =
+            new HashSet<ActivityRecordSearchTerm>();
+    
+    /**
+     * The maximum number of history records that should be returned by a call
+     * to asCollection().
+     */
+    private int limit = Integer.MAX_VALUE;
+    
+    /**
+     * A list of predicates to apply while sorting the resulting records,
+     * describing the properties involved and the sort order for those
+     * properties.
+     */
+    private final List<ActivityRecordSortPredicate> sortPredicates =
+            new ArrayList<ActivityRecordSortPredicate>();
+
+    /**
+     * Retrieves the history records matching the given criteria. Retrieves up
+     * to <code>limit</code> history records matching the given terms and sorted
+     * by the given predicates. Only history records associated with data that
+     * the given user can read are returned.
+     *
+     * @param user
+     *     The user retrieving the history.
+     *
+     * @param requiredContents
+     *     The search terms that must be contained somewhere within each of the
+     *     returned records.
+     *
+     * @param sortPredicates
+     *     A list of predicates to sort the returned records by, in order of
+     *     priority.
+     *
+     * @param limit
+     *     The maximum number of records that should be returned.
+     *
+     * @return
+     *     A collection of all history records matching the given criteria.
+     *
+     * @throws GuacamoleException
+     *     If permission to read the history records is denied.
+     */
+    protected abstract Collection<RecordType> retrieveHistory(
+            AuthenticatedUser user,
+            Set<ActivityRecordSearchTerm> requiredContents,
+            List<ActivityRecordSortPredicate> sortPredicates,
+            int limit) throws GuacamoleException;
+
+    @Override
+    public Collection<RecordType> asCollection()
+            throws GuacamoleException {
+        return retrieveHistory(getCurrentUser(), requiredContents,
+                sortPredicates, limit);
+    }
+
+    @Override
+    public ModeledActivityRecordSet<RecordType> contains(String value)
+            throws GuacamoleException {
+        requiredContents.add(new ActivityRecordSearchTerm(value));
+        return this;
+    }
+
+    @Override
+    public ModeledActivityRecordSet<RecordType> limit(int limit) throws GuacamoleException {
+        this.limit = Math.min(this.limit, limit);
+        return this;
+    }
+
+    @Override
+    public ModeledActivityRecordSet<RecordType> sort(SortableProperty property, boolean desc)
+            throws GuacamoleException {
+        
+        sortPredicates.add(new ActivityRecordSortPredicate(
+            property,
+            desc
+        ));
+        
+        return this;
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/2414c9a2/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
index df2a0a9..f4574f4 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
@@ -20,17 +20,14 @@
 package org.apache.guacamole.auth.jdbc.connection;
 
 import com.google.inject.Inject;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
 import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
-import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
-import org.apache.guacamole.net.auth.ActivityRecordSet;
-import org.apache.guacamole.net.auth.ActivityRecordSet.SortableProperty;
+import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecordSet;
+import org.apache.guacamole.net.auth.AuthenticatedUser;
 import org.apache.guacamole.net.auth.ConnectionRecord;
 
 /**
@@ -38,8 +35,7 @@ import org.apache.guacamole.net.auth.ConnectionRecord;
  * asCollection() will query connection history records from the database. Which
  * records are returned will be determined by the values passed in earlier.
  */
-public class ConnectionRecordSet extends RestrictedObject
-        implements ActivityRecordSet<ConnectionRecord> {
+public class ConnectionRecordSet extends ModeledActivityRecordSet<ConnectionRecord> {
 
     /**
      * Service for managing connection objects.
@@ -47,60 +43,15 @@ public class ConnectionRecordSet extends RestrictedObject
     @Inject
     private ConnectionService connectionService;
     
-    /**
-     * The set of strings that each must occur somewhere within the returned 
-     * connection records, whether within the associated username, the name of 
-     * the associated connection, or any associated date. If non-empty, any 
-     * connection record not matching each of the strings within the collection 
-     * will be excluded from the results.
-     */
-    private final Set<ActivityRecordSearchTerm> requiredContents =
-            new HashSet<ActivityRecordSearchTerm>();
-    
-    /**
-     * The maximum number of connection history records that should be returned
-     * by a call to asCollection().
-     */
-    private int limit = Integer.MAX_VALUE;
-    
-    /**
-     * A list of predicates to apply while sorting the resulting connection
-     * records, describing the properties involved and the sort order for those 
-     * properties.
-     */
-    private final List<ActivityRecordSortPredicate> connectionRecordSortPredicates =
-            new ArrayList<ActivityRecordSortPredicate>();
-    
     @Override
-    public Collection<ConnectionRecord> asCollection()
+    protected Collection<ConnectionRecord> retrieveHistory(
+            AuthenticatedUser user, Set<ActivityRecordSearchTerm> requiredContents,
+            List<ActivityRecordSortPredicate> sortPredicates, int limit)
             throws GuacamoleException {
-        return connectionService.retrieveHistory(getCurrentUser(),
-                requiredContents, connectionRecordSortPredicates, limit);
-    }
 
-    @Override
-    public ConnectionRecordSet contains(String value)
-            throws GuacamoleException {
-        requiredContents.add(new ActivityRecordSearchTerm(value));
-        return this;
-    }
-
-    @Override
-    public ConnectionRecordSet limit(int limit) throws GuacamoleException {
-        this.limit = Math.min(this.limit, limit);
-        return this;
-    }
-
-    @Override
-    public ConnectionRecordSet sort(SortableProperty property, boolean desc)
-            throws GuacamoleException {
-        
-        connectionRecordSortPredicates.add(new ActivityRecordSortPredicate(
-            property,
-            desc
-        ));
-        
-        return this;
+        // Retrieve history from database
+        return connectionService.retrieveHistory(getCurrentUser(),
+                requiredContents, sortPredicates, limit);
 
     }
 


[09/16] guacamole-client git commit: GUACAMOLE-394: No need to explicitly set ID - it's automatically pulled from the username.

Posted by vn...@apache.org.
GUACAMOLE-394: No need to explicitly set ID - it's automatically pulled from the username.

Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/3ccb4d4a
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/3ccb4d4a
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/3ccb4d4a

Branch: refs/heads/staging/0.9.14
Commit: 3ccb4d4ac1d04ecc172cd2f8f2f16ecdf2895efd
Parents: 446a9d0
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 15:16:53 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java     | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/3ccb4d4a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
index 0bf01fb..0b3b121 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
@@ -132,7 +132,6 @@ public class ModeledUserContext extends RestrictedObject
 
         // Create login record for user
         userRecord = new ActivityRecordModel();
-        userRecord.setUserID(currentUser.getUser().getModel().getObjectID());
         userRecord.setUsername(currentUser.getIdentifier());
         userRecord.setStartDate(new Date());
         userRecord.setRemoteHost(currentUser.getCredentials().getRemoteHostname());


[14/16] guacamole-client git commit: GUACAMOLE-394: Disambiguate "user_id" column, now that connection query joins the connection history table.

Posted by vn...@apache.org.
GUACAMOLE-394: Disambiguate "user_id" column, now that connection query joins the connection history table.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/58054719
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/58054719
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/58054719

Branch: refs/heads/staging/0.9.14
Commit: 58054719b3949d6407bbeaa872e423077458d7a1
Parents: 28e7d21
Author: Michael Jumper <mj...@apache.org>
Authored: Mon Sep 18 11:56:14 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml | 2 +-
 .../org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml | 2 +-
 .../org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/58054719/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index 7c20935..cbffdd4 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -146,7 +146,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
             AND permission = 'READ'
         GROUP BY guacamole_connection.connection_id;
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/58054719/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index b9356b0..dc8fdd4 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -146,7 +146,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
             AND permission = 'READ'
         GROUP BY guacamole_connection.connection_id;
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/58054719/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index b31b45f..7e0e7fd 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -146,7 +146,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND [guacamole_connection_permission].user_id = #{user.objectID,jdbcType=INTEGER}
             AND permission = 'READ'
         GROUP BY [guacamole_connection].connection_id;
 


[15/16] guacamole-client git commit: GUACAMOLE-394: Determine last active date for users based on history table.

Posted by vn...@apache.org.
GUACAMOLE-394: Determine last active date for users based on history table.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/8694bc80
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/8694bc80
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/8694bc80

Branch: refs/heads/staging/0.9.14
Commit: 8694bc802a753a9acd6950c5c7d88843df886cdc
Parents: a3dd919
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 13:07:15 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:57 2017 -0800

----------------------------------------------------------------------
 .../guacamole/auth/jdbc/user/ModeledUser.java   |  2 +-
 .../guacamole/auth/jdbc/user/UserModel.java     | 32 ++++++++++++++++++++
 .../guacamole/auth/jdbc/user/UserMapper.xml     | 32 +++++++++++++-------
 .../guacamole/auth/jdbc/user/UserMapper.xml     | 32 +++++++++++++-------
 .../guacamole/auth/jdbc/user/UserMapper.xml     | 32 +++++++++++++-------
 5 files changed, 96 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/8694bc80/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
index fc43e36..7d80fac 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
@@ -796,7 +796,7 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
 
     @Override
     public Date getLastActive() {
-        return null;
+        return getModel().getLastActive();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/8694bc80/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
index afaeb55..a4f9c7a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
@@ -115,6 +115,12 @@ public class UserModel extends ObjectModel {
     private String organizationalRole;
 
     /**
+     * The date and time that this user was last active, or null if this user
+     * has never logged in.
+     */
+    private Date lastActive;
+
+    /**
      * Creates a new, empty user.
      */
     public UserModel() {
@@ -465,4 +471,30 @@ public class UserModel extends ObjectModel {
         this.organizationalRole = organizationalRole;
     }
 
+    /**
+     * Returns the date and time that this user was last active, or null if
+     * this user has never logged in.
+     *
+     * @return
+     *     The date and time that this user was last active, or null if this
+     *     user has never logged in.
+     */
+    public Date getLastActive() {
+        return lastActive;
+    }
+
+    /**
+     * Sets the date and time that this user was last active. This value is
+     * expected to be set automatically via queries, derived from user history
+     * records. It does NOT correspond to an actual column, and values set
+     * manually through invoking this function will not persist.
+     *
+     * @param lastActive
+     *     The date and time that this user was last active, or null if this
+     *     user has never logged in.
+     */
+    public void setLastActive(Date lastActive) {
+        this.lastActive = lastActive;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/8694bc80/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
index 4ab1182..c9e4f70 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
@@ -41,6 +41,7 @@
         <result column="email_address"       property="emailAddress"       jdbcType="VARCHAR"/>
         <result column="organization"        property="organization"       jdbcType="VARCHAR"/>
         <result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
+        <result column="last_active"         property="lastActive"         jdbcType="TIMESTAMP"/>
     </resultMap>
 
     <!-- Select all usernames -->
@@ -63,8 +64,8 @@
     <select id="select" resultMap="UserResultMap">
 
         SELECT
-            user_id,
-            username,
+            guacamole_user.user_id,
+            guacamole_user.username,
             password_hash,
             password_salt,
             password_date,
@@ -78,13 +79,16 @@
             full_name,
             email_address,
             organization,
-            organizational_role
+            organizational_role,
+            MAX(start_date) AS last_active
         FROM guacamole_user
-        WHERE username IN
+        LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
+        WHERE guacamole_user.username IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
+        GROUP BY guacamole_user.user_id
 
     </select>
 
@@ -93,7 +97,7 @@
 
         SELECT
             guacamole_user.user_id,
-            username,
+            guacamole_user.username,
             password_hash,
             password_salt,
             password_date,
@@ -107,16 +111,19 @@
             full_name,
             email_address,
             organization,
-            organizational_role
+            organizational_role,
+            MAX(start_date) AS last_active
         FROM guacamole_user
         JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
-        WHERE username IN
+        LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
+        WHERE guacamole_user.username IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
             AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
             AND permission = 'READ'
+        GROUP BY guacamole_user.user_id
 
     </select>
 
@@ -124,8 +131,8 @@
     <select id="selectOne" resultMap="UserResultMap">
 
         SELECT
-            user_id,
-            username,
+            guacamole_user.user_id,
+            guacamole_user.username,
             password_hash,
             password_salt,
             password_date,
@@ -139,10 +146,13 @@
             full_name,
             email_address,
             organization,
-            organizational_role
+            organizational_role,
+            MAX(start_date) AS last_active
         FROM guacamole_user
+        LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
         WHERE
-            username = #{username,jdbcType=VARCHAR}
+            guacamole_user.username = #{username,jdbcType=VARCHAR}
+        GROUP BY guacamole_user.user_id
 
     </select>
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/8694bc80/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
index 569a8ac..c106a8f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
@@ -41,6 +41,7 @@
         <result column="email_address"       property="emailAddress"       jdbcType="VARCHAR"/>
         <result column="organization"        property="organization"       jdbcType="VARCHAR"/>
         <result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
+        <result column="last_active"         property="lastActive"         jdbcType="TIMESTAMP"/>
     </resultMap>
 
     <!-- Select all usernames -->
@@ -63,8 +64,8 @@
     <select id="select" resultMap="UserResultMap">
 
         SELECT
-            user_id,
-            username,
+            guacamole_user.user_id,
+            guacamole_user.username,
             password_hash,
             password_salt,
             password_date,
@@ -78,13 +79,16 @@
             full_name,
             email_address,
             organization,
-            organizational_role
+            organizational_role,
+            MAX(start_date) AS last_active
         FROM guacamole_user
-        WHERE username IN
+        LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
+        WHERE guacamole_user.username IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
+        GROUP BY guacamole_user.user_id
 
     </select>
 
@@ -93,7 +97,7 @@
 
         SELECT
             guacamole_user.user_id,
-            username,
+            guacamole_user.username,
             password_hash,
             password_salt,
             password_date,
@@ -107,16 +111,19 @@
             full_name,
             email_address,
             organization,
-            organizational_role
+            organizational_role,
+            MAX(start_date) AS last_active
         FROM guacamole_user
         JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
-        WHERE username IN
+        LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
+        WHERE guacamole_user.username IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
             AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
             AND permission = 'READ'
+        GROUP BY guacamole_user.user_id
 
     </select>
 
@@ -124,8 +131,8 @@
     <select id="selectOne" resultMap="UserResultMap">
 
         SELECT
-            user_id,
-            username,
+            guacamole_user.user_id,
+            guacamole_user.username,
             password_hash,
             password_salt,
             password_date,
@@ -139,10 +146,13 @@
             full_name,
             email_address,
             organization,
-            organizational_role
+            organizational_role,
+            MAX(start_date) AS last_active
         FROM guacamole_user
+        LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
         WHERE
-            username = #{username,jdbcType=VARCHAR}
+            guacamole_user.username = #{username,jdbcType=VARCHAR}
+        GROUP BY guacamole_user.user_id
 
     </select>
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/8694bc80/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
index 6df6cf2..ec60632 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
@@ -41,6 +41,7 @@
         <result column="email_address"       property="emailAddress"       jdbcType="VARCHAR"/>
         <result column="organization"        property="organization"       jdbcType="VARCHAR"/>
         <result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
+        <result column="last_active"         property="lastActive"         jdbcType="TIMESTAMP"/>
     </resultMap>
 
     <!-- Select all usernames -->
@@ -63,8 +64,8 @@
     <select id="select" resultMap="UserResultMap">
 
         SELECT
-            user_id,
-            username,
+            [guacamole_user].user_id,
+            [guacamole_user].username,
             password_hash,
             password_salt,
             password_date,
@@ -78,13 +79,16 @@
             full_name,
             email_address,
             organization,
-            organizational_role
+            organizational_role,
+            MAX(start_date) AS last_active
         FROM [guacamole_user]
-        WHERE username IN
+        LEFT JOIN [guacamole_user_history] ON [guacamole_user_history].user_id = [guacamole_user].user_id
+        WHERE [guacamole_user].username IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
+        GROUP BY [guacamole_user].user_id
 
     </select>
 
@@ -93,7 +97,7 @@
 
         SELECT
             [guacamole_user].user_id,
-            username,
+            [guacamole_user].username,
             password_hash,
             password_salt,
             password_date,
@@ -107,16 +111,19 @@
             full_name,
             email_address,
             organization,
-            organizational_role
+            organizational_role,
+            MAX(start_date) AS last_active
         FROM [guacamole_user]
         JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id
-        WHERE username IN
+        LEFT JOIN [guacamole_user_history] ON [guacamole_user_history].user_id = [guacamole_user].user_id
+        WHERE [guacamole_user].username IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
             AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
             AND permission = 'READ'
+        GROUP BY [guacamole_user].user_id
 
     </select>
 
@@ -124,8 +131,8 @@
     <select id="selectOne" resultMap="UserResultMap">
 
         SELECT
-            user_id,
-            username,
+            [guacamole_user].user_id,
+            [guacamole_user].username,
             password_hash,
             password_salt,
             password_date,
@@ -139,10 +146,13 @@
             full_name,
             email_address,
             organization,
-            organizational_role
+            organizational_role,
+            MAX(start_date) AS last_active
         FROM [guacamole_user]
+        LEFT JOIN [guacamole_user_history] ON [guacamole_user_history].user_id = [guacamole_user].user_id
         WHERE
-            username = #{username,jdbcType=VARCHAR}
+            [guacamole_user].username = #{username,jdbcType=VARCHAR}
+        GROUP BY [guacamole_user].user_id
 
     </select>