Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/prerna/auth/utils/AbstractSecurityUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -1194,10 +1194,12 @@ public static void initialize() throws Exception {
// USERENGINEPREFERENCE
// a person's own settings on an engine, such as favorite and visibility, kept
// out of ENGINEPERMISSION so that setting one adds no access row
colNames = new String[] { "USERID", "TYPE", "ENGINEID", "FAVORITE", "VISIBILITY" };
// USERDISCOVERABLE marks it as one the user lets agents find and use; off
// unless the user turns it on, and a null is off
colNames = new String[] { "USERID", "TYPE", "ENGINEID", "FAVORITE", "VISIBILITY", "USERDISCOVERABLE" };
types = new String[] { VARCHAR_255, VARCHAR_255, VARCHAR_255, BOOLEAN_DATATYPE_NAME,
BOOLEAN_DATATYPE_NAME };
defaultValues = new Object[] { null, null, null, false, true };
BOOLEAN_DATATYPE_NAME, BOOLEAN_DATATYPE_NAME };
defaultValues = new Object[] { null, null, null, false, true, false };
if (allowIfExistsTable) {
String sql = queryUtil.createTableIfNotExistsWithDefaults("USERENGINEPREFERENCE", colNames, types,
defaultValues);
Expand Down Expand Up @@ -1542,10 +1544,12 @@ public static void initialize() throws Exception {
// USERPROJECTPREFERENCE
// a person's own settings on a project, such as favorite and visibility, kept
// out of PROJECTPERMISSION so that setting one adds no access row
colNames = new String[] { "USERID", "TYPE", "PROJECTID", "FAVORITE", "VISIBILITY" };
// USERDISCOVERABLE marks it as one the user lets agents find and use; off
// unless the user turns it on, and a null is off
colNames = new String[] { "USERID", "TYPE", "PROJECTID", "FAVORITE", "VISIBILITY", "USERDISCOVERABLE" };
types = new String[] { VARCHAR_255, VARCHAR_255, VARCHAR_255, BOOLEAN_DATATYPE_NAME,
BOOLEAN_DATATYPE_NAME };
defaultValues = new Object[] { null, null, null, false, true };
BOOLEAN_DATATYPE_NAME, BOOLEAN_DATATYPE_NAME };
defaultValues = new Object[] { null, null, null, false, true, false };
if (allowIfExistsTable) {
String sql = queryUtil.createTableIfNotExistsWithDefaults("USERPROJECTPREFERENCE", colNames, types,
defaultValues);
Expand Down
32 changes: 31 additions & 1 deletion src/prerna/auth/utils/SecurityEngineUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,29 @@ public static void setEngineFavorite(User user, String engineId, boolean isFavor
isFavorite);
}

/**
* Let agents find and use an engine for the user, or stop them, for each of
* the user's logins. The choice is saved in USERENGINEPREFERENCE, apart from
* the user's permissions, and changes only this engine. An engine is not
* discoverable to the user's agents until the user turns this on.
*
* @param user the user
* @param engineId the engine
* @param discoverable true to let the user's agents find the engine, false to
* stop them
* @throws IllegalAccessException when the engine is not public and the user
* cannot view it
* @throws Exception when the preference cannot be saved
*/
public static void setEngineUserDiscoverable(User user, String engineId, boolean discoverable) throws Exception {
if (!engineIsGlobal(engineId) && !userCanViewEngine(user, engineId)) {
throw new IllegalAccessException(
"The user doesn't have the permission to change whether this engine is discoverable to their agents.");
}
setUserPreference(user, "USERENGINEPREFERENCE", List.of(Pair.with("ENGINEID", engineId)), "USERDISCOVERABLE",
discoverable);
}

/**
* update the database name
*
Expand Down Expand Up @@ -2003,6 +2026,8 @@ public static List<Map<String, Object>> getUserEngineList(User user, List<String
qs1.addSelector(new QueryColumnSelector("GROUP_PERMISSIONS__PERMISSION", "engine_group_permission"));
qs1.addSelector(
QueryFunctionSelector.makeCol2ValCoalesceSelector("USER_PREFERENCES__FAVORITE", 0, "engine_favorite"));
qs1.addSelector(QueryFunctionSelector.makeCol2ValCoalesceSelector("USER_PREFERENCES__USERDISCOVERABLE", 0,
"engine_user_discoverable"));

// Legacy aliases, every one of which repeats a column already selected above
// under its engine_* name. The commented entries are unused by either client.
Expand Down Expand Up @@ -2076,7 +2101,7 @@ public static List<Map<String, Object>> getUserEngineList(User user, List<String
qs1.addRelation(subQuery);
}

// add a join to get if favorite and the visibility
// add a join to get if favorite, the visibility and if discoverable to agents
{
SelectQueryStruct prefQs = new SelectQueryStruct();
prefQs.addSelector(new QueryColumnSelector("USERENGINEPREFERENCE__ENGINEID", "ENGINEID"));
Expand All @@ -2091,6 +2116,11 @@ public static List<Map<String, Object>> getUserEngineList(User user, List<String
castVisibility.setDataType(securityDb.getQueryUtil().getIntegerDataTypeName());
prefQs.addSelector(
QueryFunctionSelector.makeFunctionSelector(QueryFunctionHelper.MAX, castVisibility, "VISIBILITY"));
QueryFunctionSelector castUserDiscoverable = QueryFunctionSelector.makeFunctionSelector(
QueryFunctionHelper.CAST, "USERENGINEPREFERENCE__USERDISCOVERABLE", "castUserDiscoverable");
castUserDiscoverable.setDataType(securityDb.getQueryUtil().getIntegerDataTypeName());
prefQs.addSelector(QueryFunctionSelector.makeFunctionSelector(QueryFunctionHelper.MAX,
castUserDiscoverable, "USERDISCOVERABLE"));
prefQs.addGroupBy(new QueryColumnSelector("USERENGINEPREFERENCE__ENGINEID", "ENGINEID"));
prefQs.addExplicitFilter(
getUserIdAndTypeFilter(user, "USERENGINEPREFERENCE__USERID", "USERENGINEPREFERENCE__TYPE"));
Expand Down
6 changes: 4 additions & 2 deletions src/prerna/auth/utils/SecurityOwlCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ public void createColumnsAndTypes(AbstractSqlQueryUtil queryUtil) {
Pair.with("USERID", VARCHAR_255),
Pair.with("TYPE", VARCHAR_255),
Pair.with("FAVORITE", BOOLEAN_DATATYPE_NAME),
Pair.with("VISIBILITY", BOOLEAN_DATATYPE_NAME)));
Pair.with("VISIBILITY", BOOLEAN_DATATYPE_NAME),
Pair.with("USERDISCOVERABLE", BOOLEAN_DATATYPE_NAME)));

// a model usage limit: one row per key (ModelUsageLimitKey), such as a
// person's grant on a model, a team's, a model's public use or total, or a
Expand Down Expand Up @@ -193,7 +194,8 @@ public void createColumnsAndTypes(AbstractSqlQueryUtil queryUtil) {
Pair.with("USERID", VARCHAR_255),
Pair.with("TYPE", VARCHAR_255),
Pair.with("FAVORITE", BOOLEAN_DATATYPE_NAME),
Pair.with("VISIBILITY", BOOLEAN_DATATYPE_NAME)));
Pair.with("VISIBILITY", BOOLEAN_DATATYPE_NAME),
Pair.with("USERDISCOVERABLE", BOOLEAN_DATATYPE_NAME)));

addTable("PROJECTMETA", Arrays.asList(
Pair.with("PROJECTID", VARCHAR_255),
Expand Down
40 changes: 37 additions & 3 deletions src/prerna/auth/utils/SecurityProjectUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3289,6 +3289,8 @@ public static List<Map<String, Object>> getUserProjectList(User user, List<Strin
"low_project_name"));
qs1.addSelector(
QueryFunctionSelector.makeCol2ValCoalesceSelector("USER_PREFERENCES__FAVORITE", 0, "project_favorite"));
qs1.addSelector(QueryFunctionSelector.makeCol2ValCoalesceSelector("USER_PREFERENCES__USERDISCOVERABLE", 0,
"project_user_discoverable"));
qs1.addSelector(new QueryColumnSelector("USER_PERMISSIONS__PERMISSION", "user_permission"));
qs1.addSelector(new QueryColumnSelector("GROUP_PERMISSIONS__PERMISSION", "group_permission"));

Expand Down Expand Up @@ -3636,6 +3638,8 @@ public static List<Map<String, Object>> getUserProjectList(User user, String pro
qs.addSelector(new QueryColumnSelector("PROJECT__REACTORSCOMPILEDTYPE", "project_reactors_compiled_user_type"));
qs.addSelector(
QueryFunctionSelector.makeCol2ValCoalesceSelector("USER_PREFERENCES__FAVORITE", 0, "project_favorite"));
qs.addSelector(QueryFunctionSelector.makeCol2ValCoalesceSelector("USER_PREFERENCES__USERDISCOVERABLE", 0,
"project_user_discoverable"));
// for sorting
qs.addSelector(QueryFunctionSelector.makeFunctionSelector(QueryFunctionHelper.LOWER, QueryFunctionSelector
.makeCoalesceSelector("PROJECT__PROJECTDISPLAYNAME", "PROJECT__PROJECTNAME", "display_name"),
Expand Down Expand Up @@ -3670,9 +3674,10 @@ public static List<Map<String, Object>> getUserProjectList(User user, String pro

/**
* A left join, as USER_PREFERENCES, to the user's preferences on each project:
* FAVORITE is 1 when any of the user's logins favorited it, and VISIBILITY is 1
* when any of them shows it and 0 when they all hide it, both cast to int. A
* project the user has no preferences on joins to null.
* FAVORITE is 1 when any of the user's logins favorited it, VISIBILITY is 1
* when any of them shows it and 0 when they all hide it, and USERDISCOVERABLE
* is 1 when any of them lets agents find it, all cast to int. A project the
* user has no preferences on joins to null.
*
* @param securityDb the security database
* @param user the user; their logins come from the session
Expand All @@ -3692,6 +3697,11 @@ private static IRelation getUserPreferencesSubquery(IRDBMSEngine securityDb, Use
castVisibility.setDataType(securityDb.getQueryUtil().getIntegerDataTypeName());
prefQs.addSelector(
QueryFunctionSelector.makeFunctionSelector(QueryFunctionHelper.MAX, castVisibility, "VISIBILITY"));
QueryFunctionSelector castUserDiscoverable = QueryFunctionSelector.makeFunctionSelector(
QueryFunctionHelper.CAST, "USERPROJECTPREFERENCE__USERDISCOVERABLE", "castUserDiscoverable");
castUserDiscoverable.setDataType(securityDb.getQueryUtil().getIntegerDataTypeName());
prefQs.addSelector(QueryFunctionSelector.makeFunctionSelector(QueryFunctionHelper.MAX, castUserDiscoverable,
"USERDISCOVERABLE"));
prefQs.addGroupBy(new QueryColumnSelector("USERPROJECTPREFERENCE__PROJECTID", "PROJECTID"));
prefQs.addExplicitFilter(
getUserIdAndTypeFilter(user, "USERPROJECTPREFERENCE__USERID", "USERPROJECTPREFERENCE__TYPE"));
Expand Down Expand Up @@ -3927,6 +3937,30 @@ public static void setProjectFavorite(User user, String projectId, boolean isFav
isFavorite);
}

/**
* Let agents find and use a project for the user, or stop them, for each of
* the user's logins. The choice is saved in USERPROJECTPREFERENCE, apart from
* the user's permissions, and changes only this project. A project is not
* discoverable to the user's agents until the user turns this on.
*
* @param user the user
* @param projectId the project
* @param discoverable true to let the user's agents find the project, false to
* stop them
* @throws IllegalAccessException when the project is not public and the user
* cannot view it
* @throws Exception when the preference cannot be saved
*/
public static void setProjectUserDiscoverable(User user, String projectId, boolean discoverable)
throws Exception {
if (!projectIsGlobal(projectId) && !userCanViewProject(user, projectId)) {
throw new IllegalAccessException(
"The user doesn't have the permission to change whether this project is discoverable to their agents.");
}
setUserPreference(user, "USERPROJECTPREFERENCE", List.of(Pair.with("PROJECTID", projectId)),
"USERDISCOVERABLE", discoverable);
}

///////////////////////////////////////////////
///////////////////////////////////////////////
///////////////// PROJECTS/////////////////////
Expand Down
4 changes: 4 additions & 0 deletions src/prerna/reactor/project/MyProjectsReactor.java
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ private static JSONObject responseSchema() {
new JSONObject().put("type", "integer").put("enum", new JSONArray().put(0).put(1)).put("description",
"1 if user has favorited this project, 0 otherwise"));

itemProperties.put("project_user_discoverable",
new JSONObject().put("type", "integer").put("enum", new JSONArray().put(0).put(1)).put("description",
"1 if the user has made this project discoverable to their agents, 0 otherwise (the default)"));

itemProperties.put("project_cost",
new JSONObject().put("type", "string").put("description", "Cost metadata, may be empty string"));

Expand Down
5 changes: 4 additions & 1 deletion src/prerna/reactor/security/MyEnginesReactor.java
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public ReactorDefinition getReactorDefinition() {
Returns a list of engines that the user has access to.

Inputs: filterWord, limit, offset, onlyFavorites, engineType, engine, permissionFilters, metaKeys, metaFilters, noMeta, includeUserTracking, sort.
Response keys: prefer engine_* fields (engine_id, engine_name, engine_display_name, engine_type, engine_subtype, engine_cost, engine_discoverable, engine_global, engine_tool_app, engine_created_by, engine_created_by_type, engine_date_created, low_engine_name, engine_user_permission, engine_group_permission, engine_favorite).
Response keys: prefer engine_* fields (engine_id, engine_name, engine_display_name, engine_type, engine_subtype, engine_cost, engine_discoverable, engine_global, engine_tool_app, engine_created_by, engine_created_by_type, engine_date_created, low_engine_name, engine_user_permission, engine_group_permission, engine_favorite, engine_user_discoverable).
Model engines also include a capabilities object containing modelId, capability, inputModalities, outputModalities, contextWindow, maxOutputTokens, and builtinTools when model metadata is available and noMeta is false.
Any response key prefixed with app_* or database_* is legacy and should not be used.
""")
Expand Down Expand Up @@ -260,6 +260,9 @@ private static JSONObject responseSchema() {
"Group-derived permission level for this engine"));
itemProperties.put("engine_favorite", new JSONObject().put("type", "integer")
.put("enum", new JSONArray().put(0).put(1)).put("description", "1 if favorited, otherwise 0"));
itemProperties.put("engine_user_discoverable", new JSONObject().put("type", "integer")
.put("enum", new JSONArray().put(0).put(1)).put("description",
"1 if the user has made this engine discoverable to their agents, otherwise 0 (the default)"));
itemProperties.put("permission", new JSONObject().put("type", "integer").put("description",
"Effective permission level for this engine"));
itemProperties.put("upvotes",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*******************************************************************************
* Copyright 2015 Defense Health Agency (DHA)
*
* If your use of this software does not include any GPLv2 components:
* Licensed 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.
* ----------------------------------------------------------------------------
* If your use of this software includes any GPLv2 components:
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*******************************************************************************/
package prerna.reactor.security;

import prerna.auth.utils.SecurityEngineUtils;
import prerna.reactor.AbstractReactor;
import prerna.sablecc2.om.PixelDataType;
import prerna.sablecc2.om.ReactorKeysEnum;
import prerna.sablecc2.om.nounmeta.NounMetadata;
import prerna.util.UploadInputUtility;

/**
* Let agents find and use an engine for the signed in user, or stop them. This
* is the user's own preference, saved for each of their logins, and is off
* until the user turns it on.
*/
public class SetEngineUserDiscoverableReactor extends AbstractReactor {

private static final String DISCOVERABLE = "discoverable";

public SetEngineUserDiscoverableReactor() {
this.keysToGet = new String[] { ReactorKeysEnum.ENGINE.getKey(), DISCOVERABLE };
this.keyRequired = new int[] { 1, 1 };
}

@Override
public NounMetadata execute() {
organizeKeys();
String engineId = UploadInputUtility.getEngineNameOrId(this.store,
this.keyValue.get(ReactorKeysEnum.ENGINE.getKey()));
boolean discoverable = SetProjectUserDiscoverableReactor.parseDiscoverable(this.keyValue.get(DISCOVERABLE));
try {
SecurityEngineUtils.setEngineUserDiscoverable(this.insight.getUser(), engineId, discoverable);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e.getMessage());
} catch (Exception e) {
throw new IllegalArgumentException("Could not save whether the engine is discoverable to agents", e);
}
NounMetadata noun = new NounMetadata(true, PixelDataType.BOOLEAN);
noun.addAdditionalReturn(NounMetadata.getSuccessNounMessage(discoverable
? "The engine is now discoverable to your agents"
: "The engine is no longer discoverable to your agents"));
return noun;
}

@Override
public String getReactorDescription() {
return "Set whether an engine is discoverable to the user's agents. Engines are not discoverable until the user turns this on";
}

@Override
protected String getDescriptionForKey(String key) {
if (key.equals(DISCOVERABLE)) {
return "true to let the user's agents find and use the engine, false to stop them";
}
return super.getDescriptionForKey(key);
}

}
Loading
Loading