001/*-
002 * #%L
003 * Smile CDR - CDR
004 * %%
005 * Copyright (C) 2016 - 2024 Smile CDR, Inc.
006 * %%
007 * All rights reserved.
008 * #L%
009 */
010package ca.cdr.api.model.json;
011
012import ca.cdr.api.log.Logs;
013import ca.cdr.api.util.ValueUtils;
014import io.swagger.v3.oas.annotations.Operation;
015import io.swagger.v3.oas.annotations.Parameter;
016import jakarta.annotation.Nullable;
017
018import java.util.Map;
019
020public interface IHasUserData {
021
022        @Operation(summary = "getUserData", description = "Get a user supplied data value.")
023        default Object getUserData(
024                        @Parameter(name = "theName", description = "The user data attribute name") String theName) {
025                if (getClientPopulatedUserData(false) == null) {
026                        return null;
027                }
028                return getClientPopulatedUserData(true).get(theName);
029        }
030
031        @Operation(summary = "setUserData", description = "Sets a user supplied data value in the session.")
032        default void setUserData(
033                        @Parameter(name = "theName", description = "The user data attribute name") String theName,
034                        @Parameter(name = "theValue", description = "The attribute value") Object theValue) {
035                setUserDataInternal(true, theName, theValue);
036        }
037
038        default void setUserDataInternal(boolean theDoValidationCheck, String theName, Object theValue) {
039                if (theDoValidationCheck && !ValueUtils.isPrimitiveOrString(theValue)) {
040                        Logs.getSecurityTroubleshootingLog()
041                                        .warn(String.format(
042                                                        "Attempt to save complex object in UserData at %s. Suggest using JSON.stringify(obj) to save.",
043                                                        theName));
044                }
045                getClientPopulatedUserData(true).put(theName, theValue);
046        }
047
048        @Operation(summary = "clearUserData", description = "Clear all user data.")
049        default void clearUserData(
050                        @Parameter(name = "theName", description = "The user data attribute name") String theName) {
051                getClientPopulatedUserData(true).remove(theName);
052        }
053
054        @Operation(
055                        summary = "setUserDataINN",
056                        description = "Sets a user supplied data value in the session if `value` is not null.")
057        default void setUserDataINN(
058                        @Parameter(name = "theName", description = "The user data attribute name") String theName,
059                        @Parameter(name = "theValue", description = "The attribute value") Object theValue) {
060                if (theValue == null) {
061                        return;
062                }
063
064                getClientPopulatedUserData(true).put(theName, theValue);
065        }
066
067        @Operation(summary = "hasUserData", description = "Has user data for `name` been set?")
068        default boolean hasUserData(
069                        @Parameter(name = "theName", description = "The user data attribute name") String theName) {
070                if (getClientPopulatedUserData(false) == null) {
071                        return false;
072                } else {
073                        return getClientPopulatedUserData(true).containsKey(theName);
074                }
075        }
076
077        @Operation(
078                        summary = "getUserString",
079                        description = "Get a user supplied data value as a string (converting if needed) or null if unset.")
080        default String getUserString(
081                        @Parameter(name = "theName", description = "The user data attribute name") String theName) {
082                Object ud = getUserData(theName);
083                if (ud == null) {
084                        return null;
085                }
086                if (ud instanceof String) {
087                        return (String) ud;
088                }
089                return ud.toString();
090        }
091
092        @Operation(
093                        summary = "getUserInt",
094                        description = "Get a user supplied data value as a integer, converting null/unset to 0.")
095        default int getUserInt(@Parameter(name = "theName", description = "The user data attribute name") String theName) {
096                if (!hasUserData(theName)) {
097                        return 0;
098                }
099                return (Integer) getUserData(theName);
100        }
101
102        @Operation(summary = "addUserData", description = "Add all entries to the user data. A null value will be ignored.")
103        default void addUserData(
104                        @Nullable @Parameter(name = "theExtraData", description = "The data to add")
105                                        Map<String, Object> theExtraData) {
106                if (theExtraData != null && theExtraData.size() > 0) {
107                        final Map<String, Object> map = getClientPopulatedUserData(true);
108                        theExtraData.forEach(map::put);
109                }
110        }
111
112        /**
113         * Model objects wishing to implement user data can implement this interface,
114         * and only need to actually implement this method
115         */
116        Map<String, Object> getClientPopulatedUserData(boolean theCreateIfNull);
117}