Sfoglia il codice sorgente

Revert "Merge branch 'dev' into master"

This reverts commit b78e6c66db71504f07b6174fdf9046d7ff2498ca, reversing
changes made to 16a624d52b10bc85b929fa9b3c5099165492ec3b.
Alexander Belanger 4 anni fa
parent
commit
4241d4c915
38 ha cambiato i file con 198 aggiunte e 2746 eliminazioni
  1. 14 14
      cmd/app/main.go
  2. 0 154
      dashboard/src/components/Dropdown.tsx
  3. 0 200
      dashboard/src/components/events/EventCard.tsx
  4. 0 56
      dashboard/src/components/events/EventLogs.tsx
  5. 0 226
      dashboard/src/components/events/EventsContext.tsx
  6. 0 113
      dashboard/src/components/events/EventsList.tsx
  7. 0 11
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx
  8. 0 161
      dashboard/src/main/home/cluster-dashboard/expanded-chart/events/EventsTab.tsx
  9. 13 65
      dashboard/src/shared/api.tsx
  10. 4 4
      internal/analytics/identifiers.go
  11. 3 26
      internal/analytics/track_events.go
  12. 59 461
      internal/analytics/tracks.go
  13. 0 40
      internal/forms/events.go
  14. 0 19
      internal/kubernetes/agent.go
  15. 0 68
      internal/kubernetes/provisioner/global_stream.go
  16. 0 102
      internal/models/events.go
  17. 0 3
      internal/models/infra.go
  18. 0 31
      internal/repository/event.go
  19. 0 163
      internal/repository/gorm/event.go
  20. 0 153
      internal/repository/gorm/event_test.go
  21. 0 46
      internal/repository/gorm/helpers_test.go
  22. 0 1
      internal/repository/gorm/migrate.go
  23. 0 1
      internal/repository/gorm/repository.go
  24. 0 1
      internal/repository/repository.go
  25. 0 177
      server/api/agent_handler.go
  26. 6 8
      server/api/api.go
  27. 34 22
      server/api/cluster_handler.go
  28. 2 51
      server/api/deploy_handler.go
  29. 0 170
      server/api/event_handler.go
  30. 0 9
      server/api/integration_handler.go
  31. 2 11
      server/api/oauth_github_handler.go
  32. 2 4
      server/api/oauth_google_handler.go
  33. 0 5
      server/api/project_handler.go
  34. 53 62
      server/api/provision_handler.go
  35. 1 17
      server/api/registry_handler.go
  36. 3 14
      server/api/release_handler.go
  37. 2 5
      server/api/user_handler.go
  38. 0 72
      server/router/router.go

+ 14 - 14
cmd/app/main.go

@@ -58,19 +58,6 @@ func main() {
 
 	repo := gorm.NewRepository(db, &key)
 
-	a, err := api.New(&api.AppConfig{
-		Logger:     logger,
-		Repository: repo,
-		ServerConf: appConf.Server,
-		RedisConf:  &appConf.Redis,
-		CapConf:    appConf.Capabilities,
-		DBConf:     appConf.Db,
-	})
-
-	if err != nil {
-		logger.Fatal().Err(err).Msg("")
-	}
-
 	if appConf.Redis.Enabled {
 		redis, err := adapter.NewRedisClient(&appConf.Redis)
 
@@ -83,7 +70,20 @@ func main() {
 
 		errorChan := make(chan error)
 
-		go prov.GlobalStreamListener(redis, *repo, a.AnalyticsClient, errorChan)
+		go prov.GlobalStreamListener(redis, *repo, errorChan)
+	}
+
+	a, err := api.New(&api.AppConfig{
+		Logger:     logger,
+		Repository: repo,
+		ServerConf: appConf.Server,
+		RedisConf:  &appConf.Redis,
+		CapConf:    appConf.Capabilities,
+		DBConf:     appConf.Db,
+	})
+
+	if err != nil {
+		logger.Fatal().Err(err).Msg("")
 	}
 
 	appRouter := router.New(a)

+ 0 - 154
dashboard/src/components/Dropdown.tsx

@@ -1,154 +0,0 @@
-import React, { useState } from "react";
-import styled from "styled-components";
-
-type Option = {
-  value: unknown;
-  label: string;
-};
-
-type DropdownProps = {
-  options: Array<Option>;
-  onSelect: (selectedOption: Option) => unknown;
-  selectLabel?: (currentLabel: string) => void;
-  selectValue?: (currentValue: any) => void;
-};
-
-const Dropdown: React.FunctionComponent<DropdownProps> = ({
-  options,
-  selectLabel,
-  selectValue,
-  onSelect,
-}) => {
-  const [isDropdownExpanded, setIsDropdownExpanded] = useState(false);
-  const [selectedOption, setSelectedOption] = useState<Option>(options[0]);
-
-  const handleSelectOption = (option: Option) => {
-    setSelectedOption(option);
-    onSelect(option);
-    typeof selectLabel === "function" && selectLabel(option.label);
-    typeof selectValue === "function" && selectValue(option.value);
-  };
-
-  const renderDropdown = () => {
-    if (isDropdownExpanded) {
-      return (
-        <>
-          <DropdownOverlay onClick={() => setIsDropdownExpanded(false)} />
-          <OptionWrapper
-            dropdownWidth="230px"
-            dropdownMaxHeight="200px"
-            onClick={() => setIsDropdownExpanded(false)}
-          >
-            {renderOptionList()}
-          </OptionWrapper>
-        </>
-      );
-    }
-  };
-
-  const renderOptionList = () => {
-    return options.map((option, i, originalArray) => {
-      return (
-        <Option
-          key={i}
-          selected={option.label === selectedOption.label}
-          onClick={() => handleSelectOption(option)}
-          lastItem={i === originalArray.length - 1}
-        >
-          {option.label}
-        </Option>
-      );
-    });
-  };
-
-  return (
-    <DropdownSelector
-      onClick={() => setIsDropdownExpanded(!isDropdownExpanded)}
-    >
-      <DropdownLabel>{selectedOption?.label}</DropdownLabel>
-      <i className="material-icons">arrow_drop_down</i>
-      {renderDropdown()}
-    </DropdownSelector>
-  );
-};
-
-export default Dropdown;
-
-const DropdownSelector = styled.div`
-  font-size: 13px;
-  font-weight: 500;
-  position: relative;
-  color: #ffffff;
-  display: flex;
-  align-items: center;
-  cursor: pointer;
-  border-radius: 5px;
-  :hover {
-    > i {
-      background: #ffffff22;
-    }
-  }
-
-  > i {
-    border-radius: 20px;
-    font-size: 20px;
-    margin-left: 10px;
-  }
-`;
-
-const DropdownLabel = styled.div`
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  overflow: hidden;
-  max-width: 200px;
-`;
-
-const DropdownOverlay = styled.div`
-  position: fixed;
-  width: 100%;
-  height: 100%;
-  z-index: 10;
-  left: 0px;
-  top: 0px;
-  cursor: default;
-`;
-
-const OptionWrapper = styled.div`
-  position: absolute;
-  left: 0;
-  top: calc(100% + 10px);
-  background: #26282f;
-  width: ${(props: { dropdownWidth: string; dropdownMaxHeight: string }) =>
-    props.dropdownWidth};
-  max-height: ${(props: { dropdownWidth: string; dropdownMaxHeight: string }) =>
-    props.dropdownMaxHeight || "300px"};
-  border-radius: 3px;
-  z-index: 999;
-  overflow-y: auto;
-  margin-bottom: 20px;
-  box-shadow: 0px 4px 10px 0px #00000088;
-`;
-
-const Option = styled.div`
-  width: 100%;
-  border-top: 1px solid #00000000;
-  border-bottom: 1px solid
-    ${(props: { selected: boolean; lastItem: boolean }) =>
-      props.lastItem ? "#ffffff00" : "#ffffff15"};
-  height: 37px;
-  font-size: 13px;
-  padding-top: 9px;
-  align-items: center;
-  padding-left: 15px;
-  cursor: pointer;
-  padding-right: 10px;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  background: ${(props: { selected: boolean; lastItem: boolean }) =>
-    props.selected ? "#ffffff11" : ""};
-
-  :hover {
-    background: #ffffff22;
-  }
-`;

+ 0 - 200
dashboard/src/components/events/EventCard.tsx

@@ -1,200 +0,0 @@
-import React, { useState } from "react";
-import styled from "styled-components";
-import { Event } from "./EventsContext";
-
-type CardProps = {
-  event: Event;
-  selectEvent: (id: number) => void;
-};
-const getReadableDate = (s: string) => {
-  let ts = new Date(s);
-  let date = ts.toLocaleDateString();
-  let time = ts.toLocaleTimeString([], {
-    hour: "numeric",
-    minute: "2-digit",
-  });
-  return `${time} ${date}`;
-};
-
-// Rename to Event Card
-const EventCard: React.FunctionComponent<CardProps> = ({
-  event,
-  selectEvent,
-}) => {
-  const [showTooltip, setShowTooltip] = useState(false);
-
-  return (
-    <StyledCard>
-      <ContentContainer>
-        <Icon status={event.event_type} className="material-icons-outlined">
-          {event.event_type === "critical" ? "report_problem" : "info"}
-        </Icon>
-        <EventInformation>
-          <EventName>
-            <Helper>{event.resource_type}:</Helper>
-            {event.name}
-          </EventName>
-          <EventReason>
-            <Helper>Reason:</Helper>
-            {event.reason}
-          </EventReason>
-        </EventInformation>
-      </ContentContainer>
-      <ActionContainer hasOneChild={event.event_type === "normal"}>
-        {event.event_type === "critical" && (
-          <HistoryButton
-            onClick={() => selectEvent(event.id)}
-            onMouseEnter={() => setShowTooltip(true)}
-            onMouseLeave={() => setShowTooltip(false)}
-          >
-            <span className="material-icons-outlined">manage_search</span>
-            {showTooltip && <Tooltip>Open logs</Tooltip>}
-          </HistoryButton>
-        )}
-        <TimestampContainer>
-          <TimestampIcon className="material-icons-outlined">
-            access_time
-          </TimestampIcon>
-          <span>{getReadableDate(event.timestamp)}</span>
-        </TimestampContainer>
-      </ActionContainer>
-    </StyledCard>
-  );
-};
-
-export default EventCard;
-
-const StyledCard = styled.div`
-  background: #26282f;
-  min-height: 100px;
-  width: 100%;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  border: 1px solid #26282f;
-  box-shadow: 0 4px 15px 0px #00000055;
-  border-radius: 8px;
-  padding: 14px;
-  animation: fadeIn 0.5s;
-  @keyframes fadeIn {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
-
-const ContentContainer = styled.div`
-  display: flex;
-  height: 100%;
-  width: 100%;
-  align-items: center;
-`;
-
-const Icon = styled.span`
-  font-size: 35px;
-  margin-right: 14px;
-  color: ${({ status }: { status: "critical" | "normal" }) =>
-    status === "critical" ? "red" : "green"};
-`;
-
-const EventInformation = styled.div`
-  display: flex;
-  flex-direction: column;
-  justify-content: space-around;
-  height: 100%;
-`;
-
-const EventName = styled.div`
-  font-size: 14px;
-  font-family: "Work Sans", sans-serif;
-  font-weight: 500;
-  color: #ffffff;
-`;
-
-const Helper = styled.span`
-  font-size: 14px;
-  text-transform: capitalize;
-  color: #ffffff44;
-  margin-right: 5px;
-`;
-
-const EventReason = styled.div`
-  font-size: 18px;
-  font-family: "Work Sans", sans-serif;
-  color: #ffffff;
-  margin-top: 8px;
-`;
-
-const ActionContainer = styled.div`
-  width: max-content;
-  display: flex;
-  align-items: center;
-  white-space: nowrap;
-  height: 100%;
-  flex-direction: column;
-  justify-content: ${(props: { hasOneChild: boolean }) => {
-    return props.hasOneChild ? "flex-end" : "space-between";
-  }};
-`;
-
-const HistoryButton = styled.button`
-  position: relative;
-  border: none;
-  background: none;
-  color: white;
-  padding: 5px;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  border-radius: 50%;
-  color: #ffffff44;
-  :hover {
-    background: #32343a;
-    cursor: pointer;
-  }
-`;
-
-const Tooltip = styled.div`
-  position: absolute;
-  left: 0px;
-  word-wrap: break-word;
-  top: 38px;
-  min-height: 18px;
-  padding: 5px 7px;
-  background: #272731;
-  z-index: 999;
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  flex: 1;
-  color: white;
-  text-transform: none;
-  font-size: 12px;
-  font-family: "Work Sans", sans-serif;
-  outline: 1px solid #ffffff55;
-  opacity: 0;
-  animation: faded-in 0.2s 0.15s;
-  animation-fill-mode: forwards;
-  @keyframes faded-in {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
-
-const TimestampContainer = styled.div`
-  display: flex;
-  white-space: nowrap;
-  align-items: center;
-  justify-self: flex-end;
-`;
-
-const TimestampIcon = styled.span`
-  margin-right: 5px;
-`;

+ 0 - 56
dashboard/src/components/events/EventLogs.tsx

@@ -1,56 +0,0 @@
-import React, { useContext } from "react";
-import styled from "styled-components";
-import backArrow from "assets/back_arrow.png";
-import { EventContext } from "./EventsContext";
-
-type EventLogsProps = {};
-
-const EventLogs: React.FunctionComponent<EventLogsProps> = ({}) => {
-  const { clearSelectedEvent } = useContext(EventContext);
-  return (
-    <>
-      <ControlRow>
-        <div>
-          <BackButton onClick={clearSelectedEvent}>
-            <BackButtonImg src={backArrow} />
-          </BackButton>
-        </div>
-      </ControlRow>
-      <div>Show logs</div>
-    </>
-  );
-};
-
-export default EventLogs;
-
-const ControlRow = styled.div`
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 35px;
-  padding-left: 0px;
-`;
-
-const BackButton = styled.div`
-  display: flex;
-  width: 36px;
-  cursor: pointer;
-  height: 36px;
-  align-items: center;
-  justify-content: center;
-  border: 1px solid #ffffff55;
-  border-radius: 100px;
-  background: #ffffff11;
-
-  :hover {
-    background: #ffffff22;
-    > img {
-      opacity: 1;
-    }
-  }
-`;
-
-const BackButtonImg = styled.img`
-  width: 16px;
-  opacity: 0.75;
-`;

+ 0 - 226
dashboard/src/components/events/EventsContext.tsx

@@ -1,226 +0,0 @@
-import React, { createContext, useContext, useEffect, useState } from "react";
-import api from "shared/api";
-import { Context } from "shared/Context";
-
-export type Event = {
-  id: number;
-  project_id: number;
-  cluster_id: number;
-  owner_name: string;
-  owner_type: string;
-  event_type: "critical" | "normal";
-  resource_type: string;
-  name: string;
-  namespace: string;
-  message: string;
-  reason: string;
-  timestamp: string;
-};
-
-type EventController = { type: string; name: string };
-
-export type EventsContextType = {
-  isPorterAgentInstalled: boolean;
-  isPorterAgentInstalling: boolean;
-  isLoading: boolean;
-  eventList: Event[];
-  selectedEvent: Event | null;
-  availableControllers: EventController[];
-  enableNodeEvents: boolean;
-  selectEvent: (id: number) => void;
-  clearSelectedEvent: () => void;
-  setLimit: (limit: number) => void;
-  setResourceType: (newResourceType: "pod" | "hpa" | "node") => void;
-  installPorterAgent: () => Promise<void>;
-  setSelectedController: (controllerName: EventController) => void;
-};
-
-const defaultEventContext: EventsContextType = {
-  eventList: [],
-  isPorterAgentInstalled: false,
-  isPorterAgentInstalling: false,
-  isLoading: true,
-  selectedEvent: null,
-  enableNodeEvents: false,
-  availableControllers: [],
-  selectEvent: () => {},
-  clearSelectedEvent: () => {},
-  setLimit: () => {},
-  setResourceType: () => {},
-  installPorterAgent: async () => {},
-  setSelectedController: async () => {},
-};
-
-export const EventContext = createContext<EventsContextType>(
-  defaultEventContext
-);
-
-type Props = {
-  controllers: EventController[];
-  enableNodeEvents: boolean;
-};
-
-const EventsContextProvider: React.FC<Props> = ({
-  children,
-  controllers,
-  enableNodeEvents,
-}) => {
-  // Porter agent related
-  const [isPorterAgentInstalled, setIsPorterAgentInstalled] = useState<boolean>(
-    false
-  );
-  const [
-    isPorterAgentInstalling,
-    setIsPorterAgentInstalling,
-  ] = useState<boolean>(false);
-  const [isLoading, setIsLoading] = useState<boolean>(false);
-
-  // Event related
-  const [eventList, setEventList] = useState<Event[]>([]);
-  const [selectedEvent, setSelectedEvent] = useState<Event | null>(null);
-  const [selectedController, setSelectedController] = useState<EventController>(
-    () => controllers[0] || undefined
-  );
-
-  // Pagination related
-  const [limit, setLimit] = useState<number>(10);
-  const [resourceType, setResourceType] = useState<"pod" | "hpa" | "node">(
-    "pod"
-  );
-  // Currently only implemented one sort type
-  const [sortBy] = useState<"timestamp">("timestamp");
-
-  const { currentCluster, currentProject, setCurrentError } = useContext(
-    Context
-  );
-
-  useEffect(() => {
-    checkIfPorterAgentIsInstalled();
-  }, [currentCluster, currentProject]);
-
-  useEffect(() => {
-    if (!isPorterAgentInstalling) {
-      return () => {};
-    }
-    const interval = setInterval(() => {
-      checkIfPorterAgentIsInstalled();
-    }, 500);
-
-    return () => clearInterval(interval);
-  }, [isPorterAgentInstalling]);
-
-  useEffect(() => {
-    if (!selectedController || !isPorterAgentInstalled) {
-      return;
-    }
-
-    setIsLoading(true);
-    // Clear out event list if the resource type or the selected controller changed
-    if (
-      resourceType !== eventList[0]?.resource_type ||
-      selectedController.name !== eventList[0].name
-    ) {
-      setEventList([]);
-    }
-
-    getEventList().then(() => setIsLoading(false));
-  }, [isPorterAgentInstalled, selectedController, resourceType, sortBy, limit]);
-
-  const checkIfPorterAgentIsInstalled = async () => {
-    try {
-      await api.getPorterAgentIsInstalled(
-        "<token>",
-        {
-          cluster_id: currentCluster.id,
-        },
-        {
-          project_id: currentProject.id,
-        }
-      );
-      setIsPorterAgentInstalled(true);
-    } catch (error) {
-      setIsPorterAgentInstalled(false);
-    }
-  };
-
-  const installPorterAgent = async () => {
-    try {
-      await api.installPorterAgent(
-        "<token>",
-        {},
-        {
-          project_id: currentProject.id,
-          cluster_id: currentCluster.id,
-        }
-      );
-      setIsPorterAgentInstalling(true);
-    } catch (error) {}
-  };
-
-  const removeDuplicatedEvents = (events: Event[]) => {
-    return events.reduce<Event[]>((prev, event, arr) => {
-      if (prev.find((e) => e.id === event.id)) {
-        return prev;
-      }
-      return [...prev, event];
-    }, []);
-  };
-
-  const getEventList = async () => {
-    try {
-      const res = await api.getEvents(
-        "<token>",
-        {
-          limit,
-          skip: eventList.length,
-          type: resourceType,
-          sort_by: sortBy,
-          owner_name: selectedController?.name,
-          owner_type: selectedController?.type,
-        },
-        {
-          cluster_id: currentCluster.id,
-          project_id: currentProject.id,
-        }
-      );
-      const newEventList = removeDuplicatedEvents([...eventList, ...res.data]);
-      setEventList(newEventList);
-    } catch (error) {
-      setEventList([]);
-      setCurrentError((error as Error)?.message || JSON.stringify(error));
-    }
-  };
-
-  const selectEvent = (id: number) => {
-    const event = eventList.find((e) => e.id === id);
-    setSelectedEvent(event);
-  };
-
-  const clearSelectedEvent = () => {
-    setSelectedEvent(null);
-  };
-
-  return (
-    <EventContext.Provider
-      value={{
-        enableNodeEvents,
-        isPorterAgentInstalled,
-        isPorterAgentInstalling,
-        isLoading,
-        eventList,
-        selectedEvent,
-        availableControllers: controllers,
-        selectEvent,
-        clearSelectedEvent,
-        setLimit,
-        setResourceType,
-        installPorterAgent,
-        setSelectedController,
-      }}
-    >
-      {children}
-    </EventContext.Provider>
-  );
-};
-
-export default EventsContextProvider;

+ 0 - 113
dashboard/src/components/events/EventsList.tsx

@@ -1,113 +0,0 @@
-import React, { useContext, useEffect, useMemo, useState } from "react";
-import styled from "styled-components";
-import Dropdown from "components/Dropdown";
-import { EventContext } from "./EventsContext";
-import EventCard from "./EventCard";
-
-const EventsList: React.FunctionComponent = ({}) => {
-  const {
-    eventList,
-    selectEvent,
-    setResourceType,
-    setLimit,
-    availableControllers,
-    setSelectedController,
-    enableNodeEvents,
-  } = useContext(EventContext);
-
-  const handleResourceTypeSelection = (option: {
-    label: string;
-    value: "pod" | "hpa";
-  }) => {
-    setResourceType(option.value);
-  };
-
-  const handleSetLimit = (option: { label: string; value: number }) => {
-    setLimit(option.value);
-  };
-
-  const handleControllerSelection = (option: {
-    label: string;
-    value: { type: string; name: string };
-  }) => {
-    setSelectedController(option.value);
-  };
-
-  const resourceTypes = useMemo(() => {
-    if (enableNodeEvents) {
-      return [
-        { label: "Pods", value: "pod" },
-        { label: "HPA", value: "hpa" },
-        { label: "Node", value: "node" },
-      ];
-    }
-    return [
-      { label: "Pods", value: "pod" },
-      { label: "HPA", value: "hpa" },
-    ];
-  }, [enableNodeEvents]);
-
-  const controllers = useMemo(() => {
-    return availableControllers.map((c) => ({
-      label: c.name,
-      value: c,
-    }));
-  }, [availableControllers]);
-
-  return (
-    <div>
-      <ControlRow>
-        <Dropdown
-          options={resourceTypes}
-          onSelect={handleResourceTypeSelection}
-        />
-        <RightFilters>
-          <Dropdown
-            options={[
-              { label: "10 events", value: 10 },
-              { label: "20 events", value: 20 },
-              { label: "50 events", value: 50 },
-            ]}
-            onSelect={handleSetLimit}
-          />
-          <Dropdown
-            options={controllers}
-            onSelect={handleControllerSelection}
-          />
-        </RightFilters>
-      </ControlRow>
-      <EventsGrid>
-        {eventList.map((event) => {
-          return (
-            <EventCard key={event.id} event={event} selectEvent={selectEvent} />
-          );
-        })}
-      </EventsGrid>
-    </div>
-  );
-};
-
-export default EventsList;
-
-const ControlRow = styled.div`
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  margin-bottom: 35px;
-  padding-left: 0px;
-`;
-
-const EventsGrid = styled.div`
-  display: grid;
-  grid-row-gap: 15px;
-  grid-template-columns: 1;
-`;
-
-const RightFilters = styled.div`
-  display: flex;
-  > div {
-    :not(:last-child) {
-      margin-right: 15px;
-    }
-  }
-`;

+ 0 - 11
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -33,7 +33,6 @@ import useAuth from "shared/auth/useAuth";
 import TitleSection from "components/TitleSection";
 import { integrationList } from "shared/common";
 import DeploymentType from "./DeploymentType";
-import EventsTab from "./events/EventsTab";
 
 type Props = {
   namespace: string;
@@ -432,14 +431,6 @@ const ExpandedChart: React.FC<Props> = (props) => {
             disabled={!isAuthorized("application", "", ["get", "update"])}
           />
         );
-      case "events":
-        const parsedControllers = Object.values(controllers).map((c) => {
-          return {
-            name: c?.metadata?.name,
-            type: c?.kind,
-          };
-        });
-        return <EventsTab controllers={parsedControllers} />;
       default:
     }
   };
@@ -448,8 +439,6 @@ const ExpandedChart: React.FC<Props> = (props) => {
     // Collate non-form tabs
     let rightTabOptions = [] as any[];
     let leftTabOptions = [] as any[];
-    leftTabOptions.push({ label: "Events", value: "events" });
-
     leftTabOptions.push({ label: "Status", value: "status" });
 
     if (props.isMetricsInstalled) {

+ 0 - 161
dashboard/src/main/home/cluster-dashboard/expanded-chart/events/EventsTab.tsx

@@ -1,161 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-
-import EventLogs from "components/events/EventLogs";
-import EventsList from "components/events/EventsList";
-import EventsContextProvider, {
-  EventContext,
-  EventsContextType,
-} from "components/events/EventsContext";
-import loadingSrc from "assets/loading.gif";
-
-type EventsTabProps = {
-  controllers: { type: string; name: string }[];
-};
-
-const EventsTab: React.FunctionComponent<EventsTabProps> = ({
-  controllers,
-}) => {
-  const renderContent = ({
-    isLoading,
-    isPorterAgentInstalled,
-    isPorterAgentInstalling,
-    selectedEvent,
-    installPorterAgent,
-  }: EventsContextType) => {
-    if (isPorterAgentInstalling) {
-      return (
-        <Placeholder>
-          <div>
-            <Header>
-              <Spinner src={loadingSrc} /> Installing porter agent
-            </Header>
-            This should be quick, if it takes too long please contact the porter
-            team.
-          </div>
-        </Placeholder>
-      );
-    }
-
-    if (isLoading) {
-      return (
-        <Placeholder>
-          <div>
-            <Header>
-              <Spinner src={loadingSrc} />
-            </Header>
-          </div>
-        </Placeholder>
-      );
-    }
-
-    if (!isPorterAgentInstalled) {
-      return (
-        <Placeholder>
-          <div>
-            <Header>We coulnd't detect porter agent :(</Header>
-            In order to use the events tab you should install the porter agent!
-            <InstallPorterAgentButton onClick={() => installPorterAgent()}>
-              <i className="material-icons">add</i> Install porter agent
-            </InstallPorterAgentButton>
-          </div>
-        </Placeholder>
-      );
-    }
-
-    if (!selectedEvent) {
-      return <EventsList />;
-    }
-
-    return <EventLogs />;
-  };
-
-  return (
-    <EventsPageWrapper>
-      <EventsContextProvider controllers={controllers} enableNodeEvents={false}>
-        <EventContext.Consumer>
-          {(context) => renderContent(context)}
-        </EventContext.Consumer>
-      </EventsContextProvider>
-    </EventsPageWrapper>
-  );
-};
-
-export default EventsTab;
-
-const EventsPageWrapper = styled.div`
-  margin-top: 35px;
-  padding-bottom: 80px;
-`;
-
-const InstallPorterAgentButton = styled.button`
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-  justify-content: space-between;
-  font-size: 13px;
-  cursor: pointer;
-  font-family: "Work Sans", sans-serif;
-  border: none;
-  border-radius: 20px;
-  color: white;
-  height: 35px;
-  padding: 0px 8px;
-  padding-bottom: 1px;
-  margin-top: 10px;
-  font-weight: 500;
-  padding-right: 15px;
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
-  cursor: ${(props: { disabled?: boolean }) =>
-    props.disabled ? "not-allowed" : "pointer"};
-
-  background: ${(props: { disabled?: boolean }) =>
-    props.disabled ? "#aaaabbee" : "#616FEEcc"};
-  :hover {
-    background: ${(props: { disabled?: boolean }) =>
-      props.disabled ? "" : "#505edddd"};
-  }
-
-  > i {
-    color: white;
-    width: 18px;
-    height: 18px;
-    font-weight: 600;
-    font-size: 12px;
-    border-radius: 20px;
-    display: flex;
-    align-items: center;
-    margin-right: 5px;
-    justify-content: center;
-  }
-`;
-
-const Placeholder = styled.div`
-  min-height: 400px;
-  height: 50vh;
-  padding: 30px;
-  padding-bottom: 90px;
-  font-size: 13px;
-  color: #ffffff44;
-  width: 100%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-`;
-
-const Header = styled.div`
-  font-weight: 500;
-  color: #aaaabb;
-  font-size: 16px;
-  margin-bottom: 15px;
-`;
-
-const Spinner = styled.img`
-  width: 15px;
-  height: 15px;
-  margin-right: 12px;
-  margin-bottom: -2px;
-`;

+ 13 - 65
dashboard/src/shared/api.tsx

@@ -246,19 +246,6 @@ const deleteSlackIntegration = baseApi<
   return `/api/projects/${pathParams.project_id}/slack_integrations/${pathParams.slack_integration_id}`;
 });
 
-const generateGHAWorkflow = baseApi<
-  FullActionConfigType,
-  {
-    cluster_id: number;
-    project_id: number;
-    name: string;
-  }
->("POST", (pathParams) => {
-  const { name, cluster_id, project_id } = pathParams;
-
-  return `/api/projects/${project_id}/ci/actions/generate?cluster_id=${cluster_id}&name=${name}`;
-});
-
 const updateNotificationConfig = baseApi<
   {
     payload: any;
@@ -286,6 +273,19 @@ const getNotificationConfig = baseApi<
   return `/api/projects/${pathParams.project_id}/releases/${pathParams.name}/notifications`;
 });
 
+const generateGHAWorkflow = baseApi<
+  FullActionConfigType,
+  {
+    cluster_id: number;
+    project_id: number;
+    name: string;
+  }
+>("POST", (pathParams) => {
+  const { name, cluster_id, project_id } = pathParams;
+
+  return `/api/projects/${project_id}/ci/actions/generate?cluster_id=${cluster_id}&name=${name}`;
+});
+
 const deployTemplate = baseApi<
   {
     templateName: string;
@@ -1034,54 +1034,6 @@ const createWebhookToken = baseApi<
     `/api/projects/${project_id}/releases/${chart_name}/webhook_token?namespace=${namespace}&cluster_id=${cluster_id}&storage=${storage}`
 );
 
-const getPorterAgentIsInstalled = baseApi<
-  {
-    cluster_id: number;
-  },
-  { project_id: number }
->("GET", (pathParams) => {
-  return `/api/projects/${pathParams.project_id}/agent/detect`;
-});
-
-const installPorterAgent = baseApi<
-  {},
-  { project_id: number, cluster_id: number }
->("POST", (pathParams) => {
-  return `/api/projects/${pathParams.project_id}/agent/deploy?cluster_id=${pathParams.cluster_id}`;
-});
-
-const getEvents = baseApi<
-  {
-    limit: number;
-    skip: number;
-    type: "pod" | "node" | "hpa";
-    owner_type: string;
-    owner_name: string;
-    sort_by: "timestamp";
-  },
-  {
-    project_id: number;
-    cluster_id: number;
-  }
->(
-  "GET",
-  (pathParams) =>
-    `/api/projects/${pathParams.project_id}/clusters/${pathParams.cluster_id}/events`
-);
-
-const getEventById = baseApi<
-  {},
-  {
-    project_id: number;
-    cluster_id: number;
-    event_id: number;
-  }
->(
-  "GET",
-  ({ project_id, cluster_id, event_id }) =>
-    `/api/projects/${project_id}/clusters/${cluster_id}/events/${event_id}`
-);
-
 // Bundle export to allow default api import (api.<method> is more readable)
 export default {
   checkAuth,
@@ -1188,8 +1140,4 @@ export default {
   removeCollaborator,
   getPolicyDocument,
   createWebhookToken,
-  getPorterAgentIsInstalled,
-  installPorterAgent,
-  getEvents,
-  getEventById,
 };

+ 4 - 4
internal/analytics/identifiers.go

@@ -18,14 +18,14 @@ type segmentIdentifyNewUser struct {
 	isGithub  bool
 }
 
-// CreateSegmentIdentifyUser creates an identifier for users
-func CreateSegmentIdentifyUser(user *models.User) *segmentIdentifyNewUser {
+// Creates a segment Identifier struct for new users. As we handle registration with github, it also accepts a param
+// to check if the new user has registered with github or not.
+func CreateSegmentIdentifyNewUser(user *models.User, registeredViaGithub bool) *segmentIdentifyNewUser {
 	userId := fmt.Sprintf("%v", user.ID)
-
 	return &segmentIdentifyNewUser{
 		userId:    userId,
 		userEmail: user.Email,
-		isGithub:  user.GithubUserID != 0,
+		isGithub:  registeredViaGithub,
 	}
 }
 

+ 3 - 26
internal/analytics/track_events.go

@@ -3,30 +3,7 @@ package analytics
 type SegmentEvent string
 
 const (
-	// onboarding flow
-	UserCreate    SegmentEvent = "New User"
-	ProjectCreate SegmentEvent = "New Project Event"
-
-	ClusterProvisioningStart   SegmentEvent = "Cluster Provisioning Started"
-	ClusterProvisioningError   SegmentEvent = "Cluster Provisioning Error"
-	ClusterProvisioningSuccess SegmentEvent = "Cluster Provisioning Success"
-
-	RegistryProvisioningStart   SegmentEvent = "Registry Provisioning Started"
-	RegistryProvisioningError   SegmentEvent = "Registry Provisioning Error"
-	RegistryProvisioningSuccess SegmentEvent = "Registry Provisioning Success"
-
-	ClusterConnectionStart   SegmentEvent = "Cluster Connection Started"
-	ClusterConnectionSuccess SegmentEvent = "Cluster Connection Success"
-
-	RegistryConnectionStart   SegmentEvent = "Registry Connection Started"
-	RegistryConnectionSuccess SegmentEvent = "Registry Connection Success"
-
-	GithubConnectionStart   SegmentEvent = "Github Connection Started"
-	GithubConnectionSuccess SegmentEvent = "Github Connection Success"
-
-	// launch flow
-	ApplicationLaunchStart   SegmentEvent = "Application Launch Started"
-	ApplicationLaunchSuccess SegmentEvent = "Application Launch Success"
-
-	ApplicationDeploymentWebhook SegmentEvent = "Triggered Re-deploy via Webhook"
+	NewUser            SegmentEvent = "New User"
+	RedeployViaWebhook SegmentEvent = "Triggered Re-deploy via Webhook"
+	NewClusterEvent    SegmentEvent = "New Cluster Event"
 )

+ 59 - 461
internal/analytics/tracks.go

@@ -7,505 +7,103 @@ import (
 	segment "gopkg.in/segmentio/analytics-go.v3"
 )
 
-// TRACK FUNCTIONS
-type UserCreateTrackOpts struct {
-	*UserScopedTrackOpts
-}
-
-func UserCreateTrack(opts *UserCreateTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-
-	return getSegmentUserTrack(
-		opts.UserScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, UserCreate),
-	)
-}
-
-type ProjectCreateTrackOpts struct {
-	*ProjectScopedTrackOpts
-}
-
-func ProjectCreateTrack(opts *ProjectCreateTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-
-	return getSegmentProjectTrack(
-		opts.ProjectScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, ProjectCreate),
-	)
-}
-
-type ClusterProvisioningStartTrackOpts struct {
-	// note that this is a project-scoped track, since the cluster has not been created yet
-	*ProjectScopedTrackOpts
-
-	ClusterType models.InfraKind
-	InfraID     uint
-}
-
-func ClusterProvisioningStartTrack(opts *ClusterProvisioningStartTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["cluster_type"] = opts.ClusterType
-	additionalProps["infra_id"] = opts.InfraID
-
-	return getSegmentProjectTrack(
-		opts.ProjectScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, ClusterProvisioningStart),
-	)
-}
-
-type ClusterProvisioningErrorTrackOpts struct {
-	// note that this is a project-scoped track, since the cluster has not been created yet
-	*ProjectScopedTrackOpts
-
-	ClusterType models.InfraKind
-	InfraID     uint
-}
-
-func ClusterProvisioningErrorTrack(opts *ClusterProvisioningErrorTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["cluster_type"] = opts.ClusterType
-	additionalProps["infra_id"] = opts.InfraID
-
-	return getSegmentProjectTrack(
-		opts.ProjectScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, ClusterProvisioningError),
-	)
-}
-
-type ClusterProvisioningSuccessTrackOpts struct {
-	*ClusterScopedTrackOpts
-
-	ClusterType models.InfraKind
-	InfraID     uint
-}
-
-func ClusterProvisioningSuccessTrack(opts *ClusterProvisioningSuccessTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["cluster_type"] = opts.ClusterType
-	additionalProps["infra_id"] = opts.InfraID
-
-	return getSegmentClusterTrack(
-		opts.ClusterScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, ClusterProvisioningSuccess),
-	)
-}
-
-type ClusterConnectionStartTrackOpts struct {
-	// note that this is a project-scoped track, since the cluster has not been created yet
-	*ProjectScopedTrackOpts
-
-	ClusterCandidateID uint
-}
-
-func ClusterConnectionStartTrack(opts *ClusterConnectionStartTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["cc_id"] = opts.ClusterCandidateID
-
-	return getSegmentProjectTrack(
-		opts.ProjectScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, ClusterConnectionStart),
-	)
-}
-
-type ClusterConnectionSuccessTrackOpts struct {
-	*ClusterScopedTrackOpts
-
-	ClusterCandidateID uint
-}
-
-func ClusterConnectionSuccessTrack(opts *ClusterConnectionSuccessTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["cc_id"] = opts.ClusterCandidateID
-
-	return getSegmentClusterTrack(
-		opts.ClusterScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, ClusterConnectionSuccess),
-	)
-}
-
-type RegistryConnectionStartTrackOpts struct {
-	// note that this is a project-scoped track, since the cluster has not been created yet
-	*ProjectScopedTrackOpts
-
-	// a random id assigned to this connection request
-	FlowID string
-}
-
-func RegistryConnectionStartTrack(opts *RegistryConnectionStartTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["flow_id"] = opts.FlowID
-
-	return getSegmentProjectTrack(
-		opts.ProjectScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, RegistryConnectionStart),
-	)
-}
-
-type RegistryConnectionSuccessTrackOpts struct {
-	*RegistryScopedTrackOpts
-
-	// a random id assigned to this connection request
-	FlowID string
-}
-
-func RegistryConnectionSuccessTrack(opts *RegistryConnectionSuccessTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["flow_id"] = opts.FlowID
-
-	return getSegmentRegistryTrack(
-		opts.RegistryScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, RegistryConnectionSuccess),
-	)
-}
-
-type GithubConnectionStartTrackOpts struct {
-	// note that this is a user-scoped track, since github repos are tied to the user
-	*UserScopedTrackOpts
-}
-
-func GithubConnectionStartTrack(opts *GithubConnectionStartTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-
-	return getSegmentUserTrack(
-		opts.UserScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, GithubConnectionStart),
-	)
-}
-
-type GithubConnectionSuccessTrackOpts struct {
-	// note that this is a user-scoped track, since github repos are tied to the user
-	*UserScopedTrackOpts
-}
-
-func GithubConnectionSuccessTrack(opts *GithubConnectionSuccessTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-
-	return getSegmentUserTrack(
-		opts.UserScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, GithubConnectionSuccess),
-	)
-}
-
-type ApplicationLaunchStartTrackOpts struct {
-	*ClusterScopedTrackOpts
-
-	FlowID string
-}
-
-func ApplicationLaunchStartTrack(opts *ApplicationLaunchStartTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["flow_id"] = opts.FlowID
-
-	return getSegmentClusterTrack(
-		opts.ClusterScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, ApplicationLaunchStart),
-	)
-}
-
-type ApplicationLaunchSuccessTrackOpts struct {
-	*ApplicationScopedTrackOpts
-
-	FlowID string
-}
-
-func ApplicationLaunchSuccessTrack(opts *ApplicationLaunchSuccessTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["flow_id"] = opts.FlowID
-
-	return getSegmentApplicationTrack(
-		opts.ApplicationScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, ApplicationLaunchSuccess),
-	)
-}
-
-type ApplicationDeploymentWebhookTrackOpts struct {
-	*ApplicationScopedTrackOpts
-
-	ImageURI string
-}
-
-func ApplicationDeploymentWebhookTrack(opts *ApplicationDeploymentWebhookTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["image_uri"] = opts.ImageURI
-
-	return getSegmentApplicationTrack(
-		opts.ApplicationScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, ApplicationDeploymentWebhook),
-	)
-}
-
-type RegistryProvisioningStartTrackOpts struct {
-	// note that this is a project-scoped track, since the registry has not been created yet
-	*ProjectScopedTrackOpts
-
-	RegistryType models.InfraKind
-	InfraID      uint
-}
-
-func RegistryProvisioningStartTrack(opts *RegistryProvisioningStartTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["registry_type"] = opts.RegistryType
-	additionalProps["infra_id"] = opts.InfraID
-
-	return getSegmentProjectTrack(
-		opts.ProjectScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, RegistryProvisioningStart),
-	)
-}
-
-type RegistryProvisioningErrorTrackOpts struct {
-	// note that this is a project-scoped track, since the registry has not been created yet
-	*ProjectScopedTrackOpts
-
-	RegistryType models.InfraKind
-	InfraID      uint
-}
-
-func RegistryProvisioningErrorTrack(opts *RegistryProvisioningErrorTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["registry_type"] = opts.RegistryType
-	additionalProps["infra_id"] = opts.InfraID
-
-	return getSegmentProjectTrack(
-		opts.ProjectScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, RegistryProvisioningError),
-	)
-}
-
-type RegistryProvisioningSuccessTrackOpts struct {
-	*RegistryScopedTrackOpts
-
-	RegistryType models.InfraKind
-	InfraID      uint
-}
-
-func RegistryProvisioningSuccessTrack(opts *RegistryProvisioningSuccessTrackOpts) segmentTrack {
-	additionalProps := make(map[string]interface{})
-	additionalProps["registry_type"] = opts.RegistryType
-	additionalProps["infra_id"] = opts.InfraID
-
-	return getSegmentRegistryTrack(
-		opts.RegistryScopedTrackOpts,
-		getDefaultSegmentTrack(additionalProps, RegistryProvisioningSuccess),
-	)
-}
-
-// HELPERS
-
 type segmentTrack interface {
 	getUserId() string
 	getEvent() SegmentEvent
 	getProperties() segment.Properties
 }
 
-type defaultTrackOpts struct {
-	AdditionalProps map[string]interface{}
-}
-
-type defaultSegmentTrack struct {
-	event      SegmentEvent
-	properties segmentProperties
-}
-
-func getDefaultSegmentTrack(additionalProps map[string]interface{}, event SegmentEvent) *defaultSegmentTrack {
-	props := newSegmentProperties()
-	props.addAdditionalProperties(additionalProps)
-
-	return &defaultSegmentTrack{
-		event:      event,
-		properties: props,
-	}
-}
-
-func (t *defaultSegmentTrack) getEvent() SegmentEvent {
-	return t.event
+type segmentNewUserTrack struct {
+	userId    string
+	userEmail string
 }
 
-func (t *defaultSegmentTrack) getProperties() segment.Properties {
-	props := segment.NewProperties()
+// CreateSegmentNewUserTrack creates a track of type "New User", which
+// tracks when a user has registered
+func CreateSegmentNewUserTrack(user *models.User) *segmentNewUserTrack {
+	userId := fmt.Sprintf("%v", user.ID)
 
-	for key, val := range t.properties {
-		props = props.Set(key, val)
+	return &segmentNewUserTrack{
+		userId:    userId,
+		userEmail: user.Email,
 	}
-
-	return props
-}
-
-type segmentProperties map[string]interface{}
-
-func newSegmentProperties() segmentProperties {
-	props := make(map[string]interface{})
-
-	return props
 }
 
-func (p segmentProperties) addProjectProperties(opts *ProjectScopedTrackOpts) {
-	p["proj_id"] = opts.ProjectID
+func (t *segmentNewUserTrack) getUserId() string {
+	return t.userId
 }
 
-func (p segmentProperties) addClusterProperties(opts *ClusterScopedTrackOpts) {
-	p["cluster_id"] = opts.ClusterID
+func (t *segmentNewUserTrack) getEvent() SegmentEvent {
+	return NewUser
 }
 
-func (p segmentProperties) addRegistryProperties(opts *RegistryScopedTrackOpts) {
-	p["registry_id"] = opts.RegistryID
+func (t *segmentNewUserTrack) getProperties() segment.Properties {
+	return segment.NewProperties().Set("email", t.userEmail)
 }
 
-func (p segmentProperties) addApplicationProperties(opts *ApplicationScopedTrackOpts) {
-	p["app_name"] = opts.Name
-	p["app_namespace"] = opts.Namespace
-	p["chart_name"] = opts.ChartName
+type segmentRedeployViaWebhookTrack struct {
+	userId     string
+	repository string
 }
 
-func (p segmentProperties) addAdditionalProperties(props map[string]interface{}) {
-	for key, val := range props {
-		p[key] = val
+// CreateSegmentRedeployViaWebhookTrack creates a track of type "Triggered Re-deploy via Webhook", which
+// tracks whenever a repository is redeployed via webhook call
+func CreateSegmentRedeployViaWebhookTrack(userId string, repository string) *segmentRedeployViaWebhookTrack {
+	return &segmentRedeployViaWebhookTrack{
+		userId:     userId,
+		repository: repository,
 	}
 }
 
-type UserScopedTrack struct {
-	*defaultSegmentTrack
-
-	userID uint
-}
-
-type UserScopedTrackOpts struct {
-	*defaultTrackOpts
-
-	UserID uint
+func (t *segmentRedeployViaWebhookTrack) getUserId() string {
+	return t.userId
 }
 
-func GetUserScopedTrackOpts(userID uint) *UserScopedTrackOpts {
-	return &UserScopedTrackOpts{
-		UserID: userID,
-	}
+func (t *segmentRedeployViaWebhookTrack) getEvent() SegmentEvent {
+	return RedeployViaWebhook
 }
 
-func (u *UserScopedTrack) getUserId() string {
-	return fmt.Sprintf("%d", u.userID)
+func (t *segmentRedeployViaWebhookTrack) getProperties() segment.Properties {
+	return segment.NewProperties().Set("repository", t.repository)
 }
 
-func getSegmentUserTrack(opts *UserScopedTrackOpts, track *defaultSegmentTrack) *UserScopedTrack {
-	return &UserScopedTrack{
-		defaultSegmentTrack: track,
-		userID:              opts.UserID,
-	}
+type segmentNewClusterEventTrack struct {
+	userId      string
+	projId      string
+	clusterName string
+	clusterType string // EKS, DOKS, or GKE
+	eventType   string // connected, provisioned, or destroyed
 }
 
-type ProjectScopedTrack struct {
-	*UserScopedTrack
-
-	projectID uint
+// NewClusterEventOpts are the parameters for creating a "New Cluster Event" track
+type NewClusterEventOpts struct {
+	UserId      string
+	ProjId      string
+	ClusterName string
+	ClusterType string // EKS, DOKS, or GKE
+	EventType   string // connected, provisioned, or destroyed
 }
 
-type ProjectScopedTrackOpts struct {
-	*UserScopedTrackOpts
-
-	ProjectID uint
-}
-
-func GetProjectScopedTrackOpts(userID, projID uint) *ProjectScopedTrackOpts {
-	return &ProjectScopedTrackOpts{
-		UserScopedTrackOpts: GetUserScopedTrackOpts(userID),
-		ProjectID:           projID,
-	}
-}
-
-func getSegmentProjectTrack(opts *ProjectScopedTrackOpts, track *defaultSegmentTrack) *ProjectScopedTrack {
-	track.properties.addProjectProperties(opts)
-
-	return &ProjectScopedTrack{
-		UserScopedTrack: getSegmentUserTrack(opts.UserScopedTrackOpts, track),
-		projectID:       opts.ProjectID,
-	}
-}
-
-type RegistryScopedTrack struct {
-	*ProjectScopedTrack
-
-	registryID uint
-}
-
-type RegistryScopedTrackOpts struct {
-	*ProjectScopedTrackOpts
-
-	RegistryID uint
-}
-
-func GetRegistryScopedTrackOpts(userID, projID, regID uint) *RegistryScopedTrackOpts {
-	return &RegistryScopedTrackOpts{
-		ProjectScopedTrackOpts: GetProjectScopedTrackOpts(userID, projID),
-		RegistryID:             regID,
+// CreateSegmentNewClusterEvent creates a track of type "New Cluster Event", which
+// tracks whenever a cluster is newly provisioned, connected, or destroyed.
+func CreateSegmentNewClusterEvent(opts *NewClusterEventOpts) *segmentNewClusterEventTrack {
+	return &segmentNewClusterEventTrack{
+		userId:      opts.UserId,
+		projId:      opts.ProjId,
+		clusterName: opts.ClusterName,
+		clusterType: opts.ClusterType,
+		eventType:   opts.EventType,
 	}
 }
 
-func getSegmentRegistryTrack(opts *RegistryScopedTrackOpts, track *defaultSegmentTrack) *RegistryScopedTrack {
-	track.properties.addRegistryProperties(opts)
-
-	return &RegistryScopedTrack{
-		ProjectScopedTrack: getSegmentProjectTrack(opts.ProjectScopedTrackOpts, track),
-		registryID:         opts.RegistryID,
-	}
+func (t *segmentNewClusterEventTrack) getUserId() string {
+	return t.userId
 }
 
-type ClusterScopedTrack struct {
-	*ProjectScopedTrack
-
-	clusterID uint
+func (t *segmentNewClusterEventTrack) getEvent() SegmentEvent {
+	return NewClusterEvent
 }
 
-type ClusterScopedTrackOpts struct {
-	*ProjectScopedTrackOpts
-
-	ClusterID uint
-}
-
-func GetClusterScopedTrackOpts(userID, projID, clusterID uint) *ClusterScopedTrackOpts {
-	return &ClusterScopedTrackOpts{
-		ProjectScopedTrackOpts: GetProjectScopedTrackOpts(userID, projID),
-		ClusterID:              clusterID,
-	}
-}
-
-func getSegmentClusterTrack(opts *ClusterScopedTrackOpts, track *defaultSegmentTrack) *ClusterScopedTrack {
-	track.properties.addClusterProperties(opts)
-
-	return &ClusterScopedTrack{
-		ProjectScopedTrack: getSegmentProjectTrack(opts.ProjectScopedTrackOpts, track),
-		clusterID:          opts.ClusterID,
-	}
-}
-
-type ApplicationScopedTrack struct {
-	*ClusterScopedTrack
-
-	name      string
-	namespace string
-}
-
-type ApplicationScopedTrackOpts struct {
-	*ClusterScopedTrackOpts
-
-	Name      string
-	Namespace string
-	ChartName string
-}
-
-func GetApplicationScopedTrackOpts(userID, projID, clusterID uint, name, namespace, chartName string) *ApplicationScopedTrackOpts {
-	return &ApplicationScopedTrackOpts{
-		ClusterScopedTrackOpts: GetClusterScopedTrackOpts(userID, projID, clusterID),
-		Name:                   name,
-		Namespace:              namespace,
-		ChartName:              chartName,
-	}
-}
-
-func getSegmentApplicationTrack(opts *ApplicationScopedTrackOpts, track *defaultSegmentTrack) *ApplicationScopedTrack {
-	track.properties.addApplicationProperties(opts)
-
-	return &ApplicationScopedTrack{
-		ClusterScopedTrack: getSegmentClusterTrack(opts.ClusterScopedTrackOpts, track),
-		name:               opts.Name,
-		namespace:          opts.Namespace,
-	}
+func (t *segmentNewClusterEventTrack) getProperties() segment.Properties {
+	return segment.NewProperties().Set("Project ID", t.projId).Set("Cluster Name", t.clusterName).Set("Cluster Type", t.clusterType).Set("Event Type", t.eventType)
 }

+ 0 - 40
internal/forms/events.go

@@ -1,40 +0,0 @@
-package forms
-
-import (
-	"strings"
-	"time"
-
-	"github.com/porter-dev/porter/internal/models"
-)
-
-// CreateEventForm is the input for creating a new event
-type CreateEventForm struct {
-	ResourceType string    `json:"resource_type"`
-	Name         string    `json:"name"`
-	OwnerType    string    `json:"owner_type"`
-	OwnerName    string    `json:"owner_name"`
-	EventType    string    `json:"event_type"`
-	Namespace    string    `json:"namespace"`
-	Message      string    `json:"message"`
-	Reason       string    `json:"reason"`
-	Timestamp    time.Time `json:"timestamp"`
-	Data         []string  `json:"data"`
-}
-
-func (c *CreateEventForm) ToEvent(projID uint, clusterID uint) *models.Event {
-	return &models.Event{
-		ProjectID:    projID,
-		ClusterID:    clusterID,
-		OwnerType:    c.OwnerType,
-		OwnerName:    c.OwnerName,
-		EventType:    c.EventType,
-		RefType:      c.ResourceType,
-		RefName:      c.Name,
-		RefNamespace: c.Namespace,
-		Message:      c.Message,
-		Reason:       c.Reason,
-		Timestamp:    c.Timestamp,
-		Data:         []byte(strings.Join(c.Data, "\n")),
-		Expiry:       time.Now().Add(24 * 14 * time.Hour),
-	}
-}

+ 0 - 19
internal/kubernetes/agent.go

@@ -249,17 +249,6 @@ func (a *Agent) ListNamespaces() (*v1.NamespaceList, error) {
 
 // CreateNamespace creates a namespace with the given name.
 func (a *Agent) CreateNamespace(name string) (*v1.Namespace, error) {
-	// check if namespace exists
-	checkNS, err := a.Clientset.CoreV1().Namespaces().Get(
-		context.TODO(),
-		name,
-		metav1.GetOptions{},
-	)
-
-	if err == nil && checkNS != nil {
-		return checkNS, nil
-	}
-
 	namespace := v1.Namespace{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: name,
@@ -273,14 +262,6 @@ func (a *Agent) CreateNamespace(name string) (*v1.Namespace, error) {
 	)
 }
 
-func (a *Agent) GetPorterAgent() (*appsv1.Deployment, error) {
-	return a.Clientset.AppsV1().Deployments("porter-agent-system").Get(
-		context.TODO(),
-		"porter-agent-controller-manager",
-		metav1.GetOptions{},
-	)
-}
-
 // DeleteNamespace deletes the namespace given the name.
 func (a *Agent) DeleteNamespace(name string) error {
 	return a.Clientset.CoreV1().Namespaces().Delete(

+ 0 - 68
internal/kubernetes/provisioner/global_stream.go

@@ -9,7 +9,6 @@ import (
 	"strings"
 
 	"github.com/aws/aws-sdk-go/service/ecr"
-	"github.com/porter-dev/porter/internal/analytics"
 	"github.com/porter-dev/porter/internal/repository"
 
 	redis "github.com/go-redis/redis/v8"
@@ -84,7 +83,6 @@ type ResourceCRUDHandler interface {
 func GlobalStreamListener(
 	client *redis.Client,
 	repo repository.Repository,
-	analyticsClient analytics.AnalyticsSegmentClient,
 	errorChan chan error,
 ) {
 	for {
@@ -165,14 +163,6 @@ func GlobalStreamListener(
 					if err != nil {
 						continue
 					}
-
-					analyticsClient.Track(analytics.RegistryProvisioningSuccessTrack(
-						&analytics.RegistryProvisioningSuccessTrackOpts{
-							RegistryScopedTrackOpts: analytics.GetRegistryScopedTrackOpts(infra.CreatedByUserID, infra.ProjectID, reg.ID),
-							RegistryType:            infra.Kind,
-							InfraID:                 infra.ID,
-						},
-					))
 				} else if kind == string(models.InfraEKS) {
 					cluster := &models.Cluster{
 						AuthMechanism:    models.AWS,
@@ -207,14 +197,6 @@ func GlobalStreamListener(
 					if err != nil {
 						continue
 					}
-
-					analyticsClient.Track(analytics.ClusterProvisioningSuccessTrack(
-						&analytics.ClusterProvisioningSuccessTrackOpts{
-							ClusterScopedTrackOpts: analytics.GetClusterScopedTrackOpts(infra.CreatedByUserID, infra.ProjectID, cluster.ID),
-							ClusterType:            infra.Kind,
-							InfraID:                infra.ID,
-						},
-					))
 				} else if kind == string(models.InfraGCR) {
 					reg := &models.Registry{
 						ProjectID:        projID,
@@ -235,14 +217,6 @@ func GlobalStreamListener(
 					if err != nil {
 						continue
 					}
-
-					analyticsClient.Track(analytics.RegistryProvisioningSuccessTrack(
-						&analytics.RegistryProvisioningSuccessTrackOpts{
-							RegistryScopedTrackOpts: analytics.GetRegistryScopedTrackOpts(infra.CreatedByUserID, infra.ProjectID, reg.ID),
-							RegistryType:            infra.Kind,
-							InfraID:                 infra.ID,
-						},
-					))
 				} else if kind == string(models.InfraGKE) {
 					cluster := &models.Cluster{
 						AuthMechanism:    models.GCP,
@@ -277,14 +251,6 @@ func GlobalStreamListener(
 					if err != nil {
 						continue
 					}
-
-					analyticsClient.Track(analytics.ClusterProvisioningSuccessTrack(
-						&analytics.ClusterProvisioningSuccessTrackOpts{
-							ClusterScopedTrackOpts: analytics.GetClusterScopedTrackOpts(infra.CreatedByUserID, infra.ProjectID, cluster.ID),
-							ClusterType:            infra.Kind,
-							InfraID:                infra.ID,
-						},
-					))
 				} else if kind == string(models.InfraDOCR) {
 					reg := &models.Registry{
 						ProjectID:       projID,
@@ -304,14 +270,6 @@ func GlobalStreamListener(
 					if err != nil {
 						continue
 					}
-
-					analyticsClient.Track(analytics.RegistryProvisioningSuccessTrack(
-						&analytics.RegistryProvisioningSuccessTrackOpts{
-							RegistryScopedTrackOpts: analytics.GetRegistryScopedTrackOpts(infra.CreatedByUserID, infra.ProjectID, reg.ID),
-							RegistryType:            infra.Kind,
-							InfraID:                 infra.ID,
-						},
-					))
 				} else if kind == string(models.InfraDOKS) {
 					cluster := &models.Cluster{
 						AuthMechanism:   models.DO,
@@ -346,14 +304,6 @@ func GlobalStreamListener(
 					if err != nil {
 						continue
 					}
-
-					analyticsClient.Track(analytics.ClusterProvisioningSuccessTrack(
-						&analytics.ClusterProvisioningSuccessTrackOpts{
-							ClusterScopedTrackOpts: analytics.GetClusterScopedTrackOpts(infra.CreatedByUserID, infra.ProjectID, cluster.ID),
-							ClusterType:            infra.Kind,
-							InfraID:                infra.ID,
-						},
-					))
 				}
 			} else if fmt.Sprintf("%v", msg.Values["status"]) == "error" {
 				infra, err := repo.Infra.ReadInfra(infraID)
@@ -369,24 +319,6 @@ func GlobalStreamListener(
 				if err != nil {
 					continue
 				}
-
-				if infra.Kind == models.InfraDOKS || infra.Kind == models.InfraGKE || infra.Kind == models.InfraEKS {
-					analyticsClient.Track(analytics.ClusterProvisioningErrorTrack(
-						&analytics.ClusterProvisioningErrorTrackOpts{
-							ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(infra.CreatedByUserID, infra.ProjectID),
-							ClusterType:            infra.Kind,
-							InfraID:                infra.ID,
-						},
-					))
-				} else if infra.Kind == models.InfraDOCR || infra.Kind == models.InfraGCR || infra.Kind == models.InfraECR {
-					analyticsClient.Track(analytics.RegistryProvisioningErrorTrack(
-						&analytics.RegistryProvisioningErrorTrackOpts{
-							ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(infra.CreatedByUserID, infra.ProjectID),
-							RegistryType:           infra.Kind,
-							InfraID:                infra.ID,
-						},
-					))
-				}
 			} else if fmt.Sprintf("%v", msg.Values["status"]) == "destroyed" {
 				infra, err := repo.Infra.ReadInfra(infraID)
 

+ 0 - 102
internal/models/events.go

@@ -1,102 +0,0 @@
-package models
-
-import (
-	"time"
-
-	"gorm.io/gorm"
-)
-
-// Event model that refers to a type of event from a Kubernetes cluster
-type Event struct {
-	gorm.Model
-
-	ProjectID uint
-	ClusterID uint
-
-	OwnerType string
-	OwnerName string
-
-	EventType    string
-	RefType      string
-	RefName      string
-	RefNamespace string
-	Message      string
-	Reason       string
-	Data         []byte
-
-	Timestamp time.Time
-	Expiry    time.Time
-}
-
-// EventExternal is an event to be shared over REST
-type EventExternal struct {
-	ID uint `json:"id"`
-
-	ProjectID uint `json:"project_id"`
-	ClusterID uint `json:"cluster_id"`
-
-	OwnerType string `json:"owner_type"`
-	OwnerName string `json:"owner_name"`
-
-	EventType    string    `json:"event_type"`
-	RefType      string    `json:"resource_type"`
-	RefName      string    `json:"name"`
-	RefNamespace string    `json:"namespace"`
-	Message      string    `json:"message"`
-	Reason       string    `json:"reason"`
-	Data         []byte    `json:"data"`
-	Timestamp    time.Time `json:"timestamp"`
-}
-
-type EventExternalSimple struct {
-	ID uint `json:"id"`
-
-	ProjectID uint `json:"project_id"`
-	ClusterID uint `json:"cluster_id"`
-
-	OwnerType string `json:"owner_type"`
-	OwnerName string `json:"owner_name"`
-
-	EventType    string    `json:"event_type"`
-	RefType      string    `json:"resource_type"`
-	RefName      string    `json:"name"`
-	RefNamespace string    `json:"namespace"`
-	Message      string    `json:"message"`
-	Reason       string    `json:"reason"`
-	Timestamp    time.Time `json:"timestamp"`
-}
-
-// Externalize generates an external Event to be shared over REST
-func (e *Event) Externalize() *EventExternal {
-	return &EventExternal{
-		ID:           e.ID,
-		ProjectID:    e.ProjectID,
-		ClusterID:    e.ClusterID,
-		OwnerName:    e.OwnerName,
-		OwnerType:    e.OwnerType,
-		EventType:    e.EventType,
-		RefType:      e.RefType,
-		RefName:      e.RefName,
-		RefNamespace: e.RefNamespace,
-		Reason:       e.Reason,
-		Timestamp:    e.Timestamp,
-		Data:         e.Data,
-	}
-}
-
-// Externalize generates an external Event to be shared over REST
-func (e *Event) ExternalizeSimple() *EventExternalSimple {
-	return &EventExternalSimple{
-		ID:           e.ID,
-		ProjectID:    e.ProjectID,
-		ClusterID:    e.ClusterID,
-		OwnerName:    e.OwnerName,
-		OwnerType:    e.OwnerType,
-		EventType:    e.EventType,
-		RefType:      e.RefType,
-		RefName:      e.RefName,
-		RefNamespace: e.RefNamespace,
-		Reason:       e.Reason,
-		Timestamp:    e.Timestamp,
-	}
-}

+ 0 - 3
internal/models/infra.go

@@ -48,9 +48,6 @@ type Infra struct {
 	// The project that this infra belongs to
 	ProjectID uint `json:"project_id"`
 
-	// The ID of the user that created this infra
-	CreatedByUserID uint
-
 	// Status is the status of the infra
 	Status InfraStatus `json:"status"`
 

+ 0 - 31
internal/repository/event.go

@@ -1,31 +0,0 @@
-package repository
-
-import "github.com/porter-dev/porter/internal/models"
-
-// ListEventOpts are the options for listing events
-type ListEventOpts struct {
-	ClusterID uint
-
-	Limit int    `schema:"limit"`
-	Skip  int    `schema:"skip"`
-	Type  string `schema:"type"`
-
-	// can only be "timestamp" for now
-	SortBy string `schema:"sort_by"`
-
-	OwnerType string `schema:"owner_type"`
-	OwnerName string `schema:"owner_name"`
-
-	// Decrypt is whether to decrypt the underlying Data field, which may not be desired
-	// for basic list operations
-	Decrypt bool
-}
-
-// EventRepository represents the set of queries on the
-// Event model
-type EventRepository interface {
-	CreateEvent(event *models.Event) (*models.Event, error)
-	ReadEvent(id uint, projID uint, clusterID uint) (*models.Event, error)
-	ListEventsByProjectID(projectID uint, opts *ListEventOpts) ([]*models.Event, error)
-	DeleteEvent(id uint) error
-}

+ 0 - 163
internal/repository/gorm/event.go

@@ -1,163 +0,0 @@
-package gorm
-
-import (
-	"strings"
-
-	"github.com/porter-dev/porter/internal/models"
-	"github.com/porter-dev/porter/internal/repository"
-	"gorm.io/gorm"
-)
-
-// EventRepository uses gorm.DB for querying the database
-type EventRepository struct {
-	db  *gorm.DB
-	key *[32]byte
-}
-
-// NewEventRepository returns an EventRepository which uses
-// gorm.DB for querying the database. It accepts an encryption key to encrypt
-// sensitive data
-func NewEventRepository(db *gorm.DB, key *[32]byte) repository.EventRepository {
-	return &EventRepository{db, key}
-}
-
-// CreateEvent creates a new kube auth mechanism
-func (repo *EventRepository) CreateEvent(
-	event *models.Event,
-) (*models.Event, error) {
-	err := repo.EncryptEventData(event, repo.key)
-
-	if err != nil {
-		return nil, err
-	}
-
-	if err := repo.db.Create(event).Error; err != nil {
-		return nil, err
-	}
-
-	return event, nil
-}
-
-// ReadEvent finds an event by id
-func (repo *EventRepository) ReadEvent(
-	id, projID, clusterID uint,
-) (*models.Event, error) {
-	event := &models.Event{}
-
-	// preload Clusters association
-	if err := repo.db.Where(
-		"id = ? AND project_id = ? AND cluster_id = ?",
-		id,
-		projID,
-		clusterID,
-	).First(&event).Error; err != nil {
-		return nil, err
-	}
-
-	err := repo.DecryptEventData(event, repo.key)
-
-	if err != nil {
-		return nil, err
-	}
-
-	return event, nil
-}
-
-// ListEventsByProjectID finds all events for a given project id
-// with the given options
-func (repo *EventRepository) ListEventsByProjectID(
-	projectID uint,
-	opts *repository.ListEventOpts,
-) ([]*models.Event, error) {
-	listOpts := opts
-
-	if listOpts.Limit == 0 {
-		listOpts.Limit = 50
-	}
-
-	events := []*models.Event{}
-
-	query := repo.db.Where("project_id = ? AND cluster_id = ?", projectID, opts.ClusterID)
-
-	if listOpts.Type != "" {
-		query = query.Where(
-			"ref_type = ?",
-			strings.ToLower(listOpts.Type),
-		)
-	}
-
-	if listOpts.OwnerName != "" && listOpts.OwnerType != "" {
-		query = query.Where(
-			"owner_name = ? AND owner_type = ?",
-			listOpts.OwnerName,
-			listOpts.OwnerType,
-		)
-	}
-
-	query = query.Limit(listOpts.Limit).Offset(listOpts.Skip)
-
-	if listOpts.SortBy == "timestamp" {
-		query = query.Order("timestamp desc").Order("id desc")
-	}
-
-	if err := query.Find(&events).Error; err != nil {
-		return nil, err
-	}
-
-	if opts.Decrypt {
-		for _, event := range events {
-			repo.DecryptEventData(event, repo.key)
-		}
-	}
-
-	return events, nil
-}
-
-// DeleteEvent deletes an event by ID
-func (repo *EventRepository) DeleteEvent(
-	id uint,
-) error {
-	if err := repo.db.Where("id = ?", id).Delete(&models.Event{}).Error; err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// EncryptEventData will encrypt the event data before
-// writing to the DB
-func (repo *EventRepository) EncryptEventData(
-	event *models.Event,
-	key *[32]byte,
-) error {
-	if len(event.Data) > 0 {
-		cipherData, err := repository.Encrypt(event.Data, key)
-
-		if err != nil {
-			return err
-		}
-
-		event.Data = cipherData
-	}
-
-	return nil
-}
-
-// DecryptEventData will decrypt the event data before
-// returning it from the DB
-func (repo *EventRepository) DecryptEventData(
-	event *models.Event,
-	key *[32]byte,
-) error {
-	if len(event.Data) > 0 {
-		plaintext, err := repository.Decrypt(event.Data, key)
-
-		if err != nil {
-			return err
-		}
-
-		event.Data = plaintext
-	}
-
-	return nil
-}

+ 0 - 153
internal/repository/gorm/event_test.go

@@ -1,153 +0,0 @@
-package gorm_test
-
-import (
-	"fmt"
-	"testing"
-	"time"
-
-	"github.com/go-test/deep"
-	"github.com/porter-dev/porter/internal/models"
-	"github.com/porter-dev/porter/internal/repository"
-	"gorm.io/gorm"
-)
-
-func TestCreateEvent(t *testing.T) {
-	tester := &tester{
-		dbFileName: "./porter_create_event.db",
-	}
-
-	setupTestEnv(tester, t)
-	initProject(tester, t)
-	initCluster(tester, t)
-	defer cleanup(tester, t)
-
-	event := &models.Event{
-		ProjectID:    tester.initProjects[0].Model.ID,
-		ClusterID:    tester.initClusters[0].Model.ID,
-		RefType:      "pod",
-		RefName:      "pod-example-1",
-		RefNamespace: "default",
-		Message:      "Pod killed",
-		Reason:       "OOM: memory limit exceeded",
-		Data:         []byte("log from pod\nlog2 from pod"),
-		Expiry:       time.Now().Add(24 * time.Hour),
-	}
-
-	copyEvent := *event
-
-	event, err := tester.repo.Event.CreateEvent(event)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	event, err = tester.repo.Event.ReadEvent(event.Model.ID, 1, 1)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	// make sure id is 1 and name is "ecr"
-	if event.Model.ID != 1 {
-		t.Errorf("incorrect registry ID: expected %d, got %d\n", 1, event.Model.ID)
-	}
-
-	event.Model = gorm.Model{}
-
-	if diff := deep.Equal(event, &copyEvent); diff != nil {
-		t.Errorf("tokens not equal:")
-		t.Error(diff)
-	}
-}
-
-func TestListEventsByProjectIDWithLimit(t *testing.T) {
-	suffix, _ := repository.GenerateRandomBytes(4)
-
-	tester := &tester{
-		dbFileName: fmt.Sprintf("./porter_list_events_%s.db", suffix),
-	}
-
-	setupTestEnv(tester, t)
-	initProject(tester, t)
-	initCluster(tester, t)
-	initEvents(tester, t)
-	defer cleanup(tester, t)
-
-	testListEventsByProjectID(tester, t, &repository.ListEventOpts{
-		ClusterID: 1,
-		Limit:     10,
-		Type:      "node",
-		Decrypt:   true,
-	}, tester.initEvents[50:60])
-}
-
-func TestListEventsByProjectIDWithSkip(t *testing.T) {
-	suffix, _ := repository.GenerateRandomBytes(4)
-
-	tester := &tester{
-		dbFileName: fmt.Sprintf("./porter_list_events_%s.db", suffix),
-	}
-
-	setupTestEnv(tester, t)
-	initProject(tester, t)
-	initCluster(tester, t)
-	initEvents(tester, t)
-	defer cleanup(tester, t)
-
-	testListEventsByProjectID(tester, t, &repository.ListEventOpts{
-		ClusterID: 1,
-		Limit:     25,
-		Skip:      10,
-		Decrypt:   true,
-	}, tester.initEvents[10:35])
-}
-
-func TestListEventsByProjectIDWithSortBy(t *testing.T) {
-	suffix, _ := repository.GenerateRandomBytes(4)
-
-	tester := &tester{
-		dbFileName: fmt.Sprintf("./porter_list_events_%s.db", suffix),
-	}
-
-	setupTestEnv(tester, t)
-	initProject(tester, t)
-	initCluster(tester, t)
-	initEvents(tester, t)
-	defer cleanup(tester, t)
-
-	testListEventsByProjectID(tester, t, &repository.ListEventOpts{
-		ClusterID: 1,
-		Limit:     1,
-		Skip:      0,
-		Type:      "node",
-		Decrypt:   true,
-		SortBy:    "timestamp",
-	}, tester.initEvents[99:])
-}
-
-func testListEventsByProjectID(tester *tester, t *testing.T, opts *repository.ListEventOpts, expEvents []*models.Event) {
-	t.Helper()
-
-	events, err := tester.repo.Event.ListEventsByProjectID(
-		tester.initProjects[0].Model.ID,
-		opts,
-	)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	// make sure data is correct
-	if len(events) != len(expEvents) {
-		t.Fatalf("length of events incorrect: expected %d, got %d\n", len(expEvents), len(events))
-	}
-
-	for _, expEvent := range expEvents {
-		expEvent.Data = []byte("log from pod\nlog2 from pod")
-	}
-
-	if diff := deep.Equal(expEvents, events); diff != nil {
-		t.Errorf("incorrect events")
-		t.Error(diff)
-	}
-}

+ 0 - 46
internal/repository/gorm/helpers_test.go

@@ -1,7 +1,6 @@
 package gorm_test
 
 import (
-	"fmt"
 	"os"
 	"testing"
 	"time"
@@ -23,7 +22,6 @@ type tester struct {
 	initGRs      []*models.GitRepo
 	initRegs     []*models.Registry
 	initClusters []*models.Cluster
-	initEvents   []*models.Event
 	initHRs      []*models.HelmRepo
 	initInfras   []*models.Infra
 	initReleases []*models.Release
@@ -65,7 +63,6 @@ func setupTestEnv(tester *tester, t *testing.T) {
 		&models.Infra{},
 		&models.GitActionConfig{},
 		&models.Invite{},
-		&models.Event{},
 		&ints.KubeIntegration{},
 		&ints.BasicIntegration{},
 		&ints.OIDCIntegration{},
@@ -499,49 +496,6 @@ func initInfra(tester *tester, t *testing.T) {
 	tester.initInfras = append(tester.initInfras, infra)
 }
 
-func initEvents(tester *tester, t *testing.T) {
-	t.Helper()
-
-	if len(tester.initProjects) == 0 {
-		initProject(tester, t)
-	}
-
-	expiry := time.Now().Add(24 * time.Hour)
-
-	initEvents := make([]*models.Event, 0)
-
-	// init 100 events for testing purposes
-	for i := 0; i < 100; i++ {
-		refType := "pod"
-
-		if i >= 50 {
-			refType = "node"
-		}
-
-		event := &models.Event{
-			ProjectID:    tester.initProjects[0].Model.ID,
-			ClusterID:    tester.initClusters[0].Model.ID,
-			RefType:      refType,
-			RefName:      fmt.Sprintf("%s-example-%d", refType, i),
-			RefNamespace: "default",
-			Message:      "Pod killed",
-			Reason:       "OOM: memory limit exceeded",
-			Data:         []byte("log from pod\nlog2 from pod"),
-			Expiry:       expiry,
-		}
-
-		event, err := tester.repo.Event.CreateEvent(event)
-
-		if err != nil {
-			t.Fatalf("%v\n", err)
-		}
-
-		initEvents = append(initEvents, event)
-	}
-
-	tester.initEvents = initEvents
-}
-
 func initInvite(tester *tester, t *testing.T) {
 	t.Helper()
 

+ 0 - 1
internal/repository/gorm/migrate.go

@@ -26,7 +26,6 @@ func AutoMigrate(db *gorm.DB) error {
 		&models.AuthCode{},
 		&models.DNSRecord{},
 		&models.PWResetToken{},
-		&models.Event{},
 		&models.NotificationConfig{},
 		&ints.KubeIntegration{},
 		&ints.BasicIntegration{},

+ 0 - 1
internal/repository/gorm/repository.go

@@ -21,7 +21,6 @@ func NewRepository(db *gorm.DB, key *[32]byte) *repository.Repository {
 		GitActionConfig:           NewGitActionConfigRepository(db),
 		Invite:                    NewInviteRepository(db),
 		AuthCode:                  NewAuthCodeRepository(db),
-		Event:                     NewEventRepository(db, key),
 		DNSRecord:                 NewDNSRecordRepository(db),
 		PWResetToken:              NewPWResetTokenRepository(db),
 		KubeIntegration:           NewKubeIntegrationRepository(db, key),

+ 0 - 1
internal/repository/repository.go

@@ -15,7 +15,6 @@ type Repository struct {
 	Invite                    InviteRepository
 	AuthCode                  AuthCodeRepository
 	DNSRecord                 DNSRecordRepository
-	Event                     EventRepository
 	PWResetToken              PWResetTokenRepository
 	KubeIntegration           KubeIntegrationRepository
 	BasicIntegration          BasicIntegrationRepository

+ 0 - 177
server/api/agent_handler.go

@@ -1,177 +0,0 @@
-package api
-
-import (
-	"fmt"
-	"net/http"
-	"net/url"
-	"strconv"
-
-	"github.com/go-chi/chi"
-	"github.com/porter-dev/porter/internal/auth/token"
-	"github.com/porter-dev/porter/internal/forms"
-	"github.com/porter-dev/porter/internal/helm"
-	"github.com/porter-dev/porter/internal/helm/loader"
-	"github.com/porter-dev/porter/internal/kubernetes"
-)
-
-// HandleDeployAgent deploys the agent in the Porter cluster
-func (app *App) HandleDeployAgent(w http.ResponseWriter, r *http.Request) {
-	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-
-	if err != nil || projID == 0 {
-		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-		return
-	}
-
-	chart, err := loader.LoadChartPublic(
-		app.ServerConf.DefaultAddonHelmRepoURL,
-		"porter-agent",
-		"",
-	)
-
-	if err != nil {
-		app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
-		return
-	}
-
-	vals, err := url.ParseQuery(r.URL.RawQuery)
-
-	if err != nil {
-		app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
-		return
-	}
-
-	releaseForm := &forms.ReleaseForm{
-		Form: &helm.Form{
-			Repo:              app.Repo,
-			DigitalOceanOAuth: app.DOConf,
-			Storage:           "secret",
-			Namespace:         "porter-agent-system",
-		},
-	}
-
-	releaseForm.PopulateHelmOptionsFromQueryParams(
-		vals,
-		app.Repo.Cluster,
-	)
-
-	agent, err := app.getAgentFromReleaseForm(
-		w,
-		r,
-		releaseForm,
-	)
-
-	if err != nil {
-		app.handleErrorFormDecoding(err, ErrUserDecode, w)
-		return
-	}
-
-	// create namespace if not exists
-	_, err = agent.K8sAgent.CreateNamespace("porter-agent-system")
-
-	if err != nil {
-		app.handleErrorFormDecoding(err, ErrUserDecode, w)
-		return
-	}
-
-	// add api token to values
-	userID, err := app.getUserIDFromRequest(r)
-
-	if err != nil {
-		app.handleErrorFormDecoding(err, ErrUserDecode, w)
-		return
-	}
-
-	jwt, _ := token.GetTokenForAPI(userID, uint(projID))
-
-	encoded, err := jwt.EncodeToken(&token.TokenGeneratorConf{
-		TokenSecret: app.ServerConf.TokenGeneratorSecret,
-	})
-
-	if err != nil {
-		app.handleErrorInternal(err, w)
-		return
-	}
-
-	porterAgentValues := map[string]interface{}{
-		"agent": map[string]interface{}{
-			"image":       "public.ecr.aws/o1j4x7p4/porter-agent:latest",
-			"porterHost":  app.ServerConf.ServerURL,
-			"porterPort":  "443",
-			"porterToken": encoded,
-			"privateRegistry": map[string]interface{}{
-				"enabled": false,
-			},
-			"clusterID": fmt.Sprintf("%d", releaseForm.Cluster.ID),
-			"projectID": fmt.Sprintf("%d", projID),
-		},
-	}
-
-	conf := &helm.InstallChartConfig{
-		Chart:     chart,
-		Name:      "porter-agent",
-		Namespace: "porter-agent-system",
-		Cluster:   releaseForm.Cluster,
-		Repo:      *app.Repo,
-		Values:    porterAgentValues,
-	}
-
-	_, err = agent.InstallChart(conf, app.DOConf)
-
-	if err != nil {
-		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
-			Code:   ErrReleaseDeploy,
-			Errors: []string{"error installing a new chart: " + err.Error()},
-		}, w)
-
-		return
-	}
-
-	w.WriteHeader(http.StatusOK)
-}
-
-// HandleDetectPorterAgentInstalled detects if the agent is installed in the cluster
-func (app *App) HandleDetectPorterAgentInstalled(w http.ResponseWriter, r *http.Request) {
-	vals, err := url.ParseQuery(r.URL.RawQuery)
-
-	if err != nil {
-		app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
-		return
-	}
-
-	// get the filter options
-	form := &forms.K8sForm{
-		OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
-			Repo:              app.Repo,
-			DigitalOceanOAuth: app.DOConf,
-		},
-	}
-
-	form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
-
-	// validate the form
-	if err := app.validator.Struct(form); err != nil {
-		app.handleErrorFormValidation(err, ErrK8sValidate, w)
-		return
-	}
-
-	// create a new agent
-	var agent *kubernetes.Agent
-
-	if app.ServerConf.IsTesting {
-		agent = app.TestAgents.K8sAgent
-	} else {
-		agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
-	}
-
-	// detect prometheus service
-	porterAgent, err := agent.GetPorterAgent()
-
-	if err != nil || porterAgent == nil {
-		http.NotFound(w, r)
-		return
-	}
-
-	w.WriteHeader(http.StatusOK)
-	return
-}

+ 6 - 8
server/api/api.go

@@ -95,13 +95,11 @@ type App struct {
 	GoogleUserConf    *oauth2.Config
 	SlackConf         *oauth2.Config
 
-	// analytics client for reporting
-	AnalyticsClient analytics.AnalyticsSegmentClient
-
-	db         *gorm.DB
-	validator  *vr.Validate
-	translator *ut.Translator
-	tokenConf  *token.TokenGeneratorConf
+	db              *gorm.DB
+	validator       *vr.Validate
+	translator      *ut.Translator
+	tokenConf       *token.TokenGeneratorConf
+	analyticsClient analytics.AnalyticsSegmentClient
 }
 
 type AppCapabilities struct {
@@ -244,7 +242,7 @@ func New(conf *AppConfig) (*App, error) {
 	}
 
 	newSegmentClient := analytics.InitializeAnalyticsSegmentClient(sc.SegmentClientKey, app.Logger)
-	app.AnalyticsClient = newSegmentClient
+	app.analyticsClient = newSegmentClient
 
 	app.updateChartRepoURLs()
 

+ 34 - 22
server/api/cluster_handler.go

@@ -2,6 +2,7 @@ package api
 
 import (
 	"encoding/json"
+	"fmt"
 	"net/http"
 	"strconv"
 
@@ -16,7 +17,7 @@ import (
 // HandleCreateProjectCluster creates a new cluster
 func (app *App) HandleCreateProjectCluster(w http.ResponseWriter, r *http.Request) {
 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-	// userID, err := app.getUserIDFromRequest(r)
+	userID, err := app.getUserIDFromRequest(r)
 
 	if err != nil || projID == 0 {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
@@ -56,6 +57,15 @@ func (app *App) HandleCreateProjectCluster(w http.ResponseWriter, r *http.Reques
 	}
 
 	app.Logger.Info().Msgf("New cluster created: %d", cluster.ID)
+	app.analyticsClient.Track(analytics.CreateSegmentNewClusterEvent(
+		&analytics.NewClusterEventOpts{
+			UserId:      fmt.Sprintf("%d", userID),
+			ProjId:      fmt.Sprintf("%d", projID),
+			ClusterName: cluster.Name,
+			ClusterType: "EKS",
+			EventType:   "connected",
+		},
+	))
 
 	w.WriteHeader(http.StatusCreated)
 
@@ -269,7 +279,14 @@ func (app *App) HandleCreateProjectClusterCandidates(w http.ResponseWriter, r *h
 
 	extClusters := make([]*models.ClusterCandidateExternal, 0)
 
-	userID, _ := app.getUserIDFromRequest(r)
+	session, err := app.Store.Get(r, app.ServerConf.CookieName)
+
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	userID, _ := session.Values["user_id"].(uint)
 
 	for _, cc := range ccs {
 		// handle write to the database
@@ -280,13 +297,6 @@ func (app *App) HandleCreateProjectClusterCandidates(w http.ResponseWriter, r *h
 			return
 		}
 
-		app.AnalyticsClient.Track(analytics.ClusterConnectionStartTrack(
-			&analytics.ClusterConnectionStartTrackOpts{
-				ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
-				ClusterCandidateID:     cc.ID,
-			},
-		))
-
 		app.Logger.Info().Msgf("New cluster candidate created: %d", cc.ID)
 
 		// if the ClusterCandidate does not have any actions to perform, create the Cluster
@@ -329,13 +339,6 @@ func (app *App) HandleCreateProjectClusterCandidates(w http.ResponseWriter, r *h
 			}
 
 			app.Logger.Info().Msgf("New cluster created: %d", cluster.ID)
-
-			app.AnalyticsClient.Track(analytics.ClusterConnectionSuccessTrack(
-				&analytics.ClusterConnectionSuccessTrackOpts{
-					ClusterScopedTrackOpts: analytics.GetClusterScopedTrackOpts(userID, uint(projID), cluster.ID),
-					ClusterCandidateID:     cc.ID,
-				},
-			))
 		}
 
 		extClusters = append(extClusters, cc.Externalize())
@@ -398,7 +401,14 @@ func (app *App) HandleResolveClusterCandidate(w http.ResponseWriter, r *http.Req
 		return
 	}
 
-	userID, _ := app.getUserIDFromRequest(r)
+	session, err := app.Store.Get(r, app.ServerConf.CookieName)
+
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	userID, _ := session.Values["user_id"].(uint)
 
 	// decode actions from request
 	resolver := &models.ClusterResolverAll{}
@@ -437,11 +447,13 @@ func (app *App) HandleResolveClusterCandidate(w http.ResponseWriter, r *http.Req
 	}
 
 	app.Logger.Info().Msgf("New cluster created: %d", cluster.ID)
-
-	app.AnalyticsClient.Track(analytics.ClusterConnectionSuccessTrack(
-		&analytics.ClusterConnectionSuccessTrackOpts{
-			ClusterScopedTrackOpts: analytics.GetClusterScopedTrackOpts(userID, uint(projID), cluster.ID),
-			ClusterCandidateID:     uint(candID),
+	app.analyticsClient.Track(analytics.CreateSegmentNewClusterEvent(
+		&analytics.NewClusterEventOpts{
+			UserId:      fmt.Sprintf("%d", userID),
+			ProjId:      fmt.Sprintf("%d", projID),
+			ClusterName: cluster.Name,
+			ClusterType: "",
+			EventType:   "connected",
 		},
 	))
 

+ 2 - 51
server/api/deploy_handler.go

@@ -3,21 +3,18 @@ package api
 import (
 	"encoding/json"
 	"fmt"
+	"gorm.io/gorm"
 	"net/http"
 	"net/url"
 	"strconv"
 	"strings"
 
-	"gorm.io/gorm"
-
 	"github.com/go-chi/chi"
-	"github.com/porter-dev/porter/internal/analytics"
 	"github.com/porter-dev/porter/internal/forms"
 	"github.com/porter-dev/porter/internal/helm"
 	"github.com/porter-dev/porter/internal/helm/loader"
 	"github.com/porter-dev/porter/internal/integrations/ci/actions"
 	"github.com/porter-dev/porter/internal/models"
-	"github.com/porter-dev/porter/internal/oauth"
 	"github.com/porter-dev/porter/internal/repository"
 	"gopkg.in/yaml.v2"
 )
@@ -25,8 +22,6 @@ import (
 // HandleDeployTemplate triggers a chart deployment from a template
 func (app *App) HandleDeployTemplate(w http.ResponseWriter, r *http.Request) {
 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-	userID, err := app.getUserIDFromRequest(r)
-	flowID := oauth.CreateRandomState()
 
 	if err != nil || projID == 0 {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
@@ -62,13 +57,6 @@ func (app *App) HandleDeployTemplate(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	app.AnalyticsClient.Track(analytics.ApplicationLaunchStartTrack(
-		&analytics.ApplicationLaunchStartTrackOpts{
-			ClusterScopedTrackOpts: analytics.GetClusterScopedTrackOpts(userID, uint(projID), uint(clusterID)),
-			FlowID:                 flowID,
-		},
-	))
-
 	getChartForm.PopulateRepoURLFromQueryParams(vals)
 
 	chart, err := loader.LoadChartPublic(getChartForm.RepoURL, getChartForm.Name, getChartForm.Version)
@@ -202,28 +190,12 @@ func (app *App) HandleDeployTemplate(w http.ResponseWriter, r *http.Request) {
 		app.createGitActionFromForm(projID, clusterID, form.ChartTemplateForm.Name, gaForm, w, r)
 	}
 
-	app.AnalyticsClient.Track(analytics.ApplicationLaunchSuccessTrack(
-		&analytics.ApplicationLaunchSuccessTrackOpts{
-			ApplicationScopedTrackOpts: analytics.GetApplicationScopedTrackOpts(
-				userID,
-				uint(projID),
-				uint(clusterID),
-				release.Name,
-				release.Namespace,
-				chart.Metadata.Name,
-			),
-			FlowID: flowID,
-		},
-	))
-
 	w.WriteHeader(http.StatusOK)
 }
 
 // HandleDeployAddon triggers a addon deployment from a template
 func (app *App) HandleDeployAddon(w http.ResponseWriter, r *http.Request) {
 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-	userID, err := app.getUserIDFromRequest(r)
-	flowID := oauth.CreateRandomState()
 
 	if err != nil || projID == 0 {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
@@ -281,13 +253,6 @@ func (app *App) HandleDeployAddon(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	app.AnalyticsClient.Track(analytics.ApplicationLaunchStartTrack(
-		&analytics.ApplicationLaunchStartTrackOpts{
-			ClusterScopedTrackOpts: analytics.GetClusterScopedTrackOpts(userID, uint(projID), uint(form.ReleaseForm.Cluster.ID)),
-			FlowID:                 flowID,
-		},
-	))
-
 	agent, err := app.getAgentFromReleaseForm(
 		w,
 		r,
@@ -316,7 +281,7 @@ func (app *App) HandleDeployAddon(w http.ResponseWriter, r *http.Request) {
 		Registries: registries,
 	}
 
-	rel, err := agent.InstallChart(conf, app.DOConf)
+	_, err = agent.InstallChart(conf, app.DOConf)
 
 	if err != nil {
 		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
@@ -327,20 +292,6 @@ func (app *App) HandleDeployAddon(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	app.AnalyticsClient.Track(analytics.ApplicationLaunchSuccessTrack(
-		&analytics.ApplicationLaunchSuccessTrackOpts{
-			ApplicationScopedTrackOpts: analytics.GetApplicationScopedTrackOpts(
-				userID,
-				uint(projID),
-				uint(form.ReleaseForm.Cluster.ID),
-				rel.Name,
-				rel.Namespace,
-				chart.Metadata.Name,
-			),
-			FlowID: flowID,
-		},
-	))
-
 	w.WriteHeader(http.StatusOK)
 }
 

+ 0 - 170
server/api/event_handler.go

@@ -1,170 +0,0 @@
-package api
-
-import (
-	"encoding/json"
-	"net/http"
-	"net/url"
-	"strconv"
-
-	"github.com/go-chi/chi"
-	"github.com/gorilla/schema"
-	"github.com/porter-dev/porter/internal/forms"
-	"github.com/porter-dev/porter/internal/models"
-	"github.com/porter-dev/porter/internal/repository"
-	"gorm.io/gorm"
-)
-
-// HandleCreateEvent creates a new event in a project
-func (app *App) HandleCreateEvent(w http.ResponseWriter, r *http.Request) {
-	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-
-	if err != nil || projID == 0 {
-		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-		return
-	}
-
-	clusterID, err := strconv.ParseUint(chi.URLParam(r, "cluster_id"), 0, 64)
-
-	if err != nil {
-		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
-			Code:   ErrReleaseReadData,
-			Errors: []string{"cluster not found"},
-		}, w)
-	}
-
-	form := &forms.CreateEventForm{}
-
-	// decode from JSON to form value
-	if err := json.NewDecoder(r.Body).Decode(form); err != nil {
-		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-		return
-	}
-
-	// validate the form
-	if err := app.validator.Struct(form); err != nil {
-		app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
-		return
-	}
-
-	// convert the form to an invite
-	event := form.ToEvent(uint(projID), uint(clusterID))
-
-	if err != nil {
-		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-		return
-	}
-
-	// handle write to the database
-	event, err = app.Repo.Event.CreateEvent(event)
-
-	if err != nil {
-		app.handleErrorDataWrite(err, w)
-		return
-	}
-
-	w.WriteHeader(http.StatusCreated)
-}
-
-// HandleListEvents lists the events that match certain conditions in a project
-func (app *App) HandleListEvents(w http.ResponseWriter, r *http.Request) {
-	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-
-	if err != nil || projID == 0 {
-		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-		return
-	}
-
-	clusterID, err := strconv.ParseUint(chi.URLParam(r, "cluster_id"), 0, 64)
-
-	if err != nil {
-		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
-			Code:   ErrReleaseReadData,
-			Errors: []string{"cluster not found"},
-		}, w)
-	}
-
-	vals, err := url.ParseQuery(r.URL.RawQuery)
-
-	opts := &repository.ListEventOpts{
-		ClusterID: uint(clusterID),
-	}
-
-	decoder := schema.NewDecoder()
-
-	decoder.IgnoreUnknownKeys(true)
-
-	if err := decoder.Decode(opts, vals); err != nil {
-		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
-			Code:   ErrReleaseReadData,
-			Errors: []string{"bad request"},
-		}, w)
-	}
-
-	// handle write to the database
-	events, err := app.Repo.Event.ListEventsByProjectID(uint(projID), opts)
-
-	if err != nil {
-		app.handleErrorDataWrite(err, w)
-		return
-	}
-
-	eventExts := make([]*models.EventExternalSimple, 0)
-
-	for _, event := range events {
-		eventExts = append(eventExts, event.ExternalizeSimple())
-	}
-
-	w.WriteHeader(http.StatusOK)
-
-	if err := json.NewEncoder(w).Encode(eventExts); err != nil {
-		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-		return
-	}
-}
-
-// HandleListEvents lists the events that match certain conditions in a project
-func (app *App) HandleGetEvent(w http.ResponseWriter, r *http.Request) {
-	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-
-	if err != nil || projID == 0 {
-		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-		return
-	}
-
-	clusterID, err := strconv.ParseUint(chi.URLParam(r, "cluster_id"), 0, 64)
-
-	if err != nil {
-		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
-			Code:   ErrReleaseReadData,
-			Errors: []string{"cluster not found"},
-		}, w)
-	}
-
-	eventID, err := strconv.ParseUint(chi.URLParam(r, "event_id"), 0, 64)
-
-	if err != nil || projID == 0 {
-		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-		return
-	}
-
-	event, err := app.Repo.Event.ReadEvent(uint(eventID), uint(projID), uint(clusterID))
-
-	if err != nil {
-		if err == gorm.ErrRecordNotFound {
-			http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
-			return
-		}
-
-		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-		return
-	}
-
-	eventExt := event.Externalize()
-
-	w.WriteHeader(http.StatusOK)
-
-	if err := json.NewEncoder(w).Encode(eventExt); err != nil {
-		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
-		return
-	}
-}

+ 0 - 9
server/api/integration_handler.go

@@ -16,7 +16,6 @@ import (
 
 	"github.com/go-chi/chi"
 	"github.com/google/go-github/github"
-	"github.com/porter-dev/porter/internal/analytics"
 	"github.com/porter-dev/porter/internal/forms"
 	"github.com/porter-dev/porter/internal/oauth"
 	"golang.org/x/oauth2"
@@ -482,14 +481,6 @@ func (app *App) HandleGithubAppAuthorize(w http.ResponseWriter, r *http.Request)
 
 // HandleGithubAppOauthInit redirects the user to the Porter github app authorization page
 func (app *App) HandleGithubAppOauthInit(w http.ResponseWriter, r *http.Request) {
-	userID, _ := app.getUserIDFromRequest(r)
-
-	app.AnalyticsClient.Track(analytics.GithubConnectionStartTrack(
-		&analytics.GithubConnectionStartTrackOpts{
-			UserScopedTrackOpts: analytics.GetUserScopedTrackOpts(userID),
-		},
-	))
-
 	http.Redirect(w, r, app.GithubAppConf.AuthCodeURL("", oauth2.AccessTypeOffline), 302)
 }
 

+ 2 - 11
server/api/oauth_github_handler.go

@@ -131,11 +131,8 @@ func (app *App) HandleGithubOAuthCallback(w http.ResponseWriter, r *http.Request
 		}
 
 		// send to segment
-		app.AnalyticsClient.Identify(analytics.CreateSegmentIdentifyUser(user))
-
-		app.AnalyticsClient.Track(analytics.UserCreateTrack(&analytics.UserCreateTrackOpts{
-			UserScopedTrackOpts: analytics.GetUserScopedTrackOpts(user.ID),
-		}))
+		app.analyticsClient.Identify(analytics.CreateSegmentIdentifyNewUser(user, true))
+		app.analyticsClient.Track(analytics.CreateSegmentNewUserTrack(user))
 
 		// log the user in
 		app.Logger.Info().Msgf("New user created: %d", user.ID)
@@ -355,12 +352,6 @@ func (app *App) HandleGithubAppOAuthCallback(w http.ResponseWriter, r *http.Requ
 		return
 	}
 
-	app.AnalyticsClient.Track(analytics.GithubConnectionSuccessTrack(
-		&analytics.GithubConnectionSuccessTrackOpts{
-			UserScopedTrackOpts: analytics.GetUserScopedTrackOpts(user.ID),
-		},
-	))
-
 	if session.Values["query_params"] != "" {
 		http.Redirect(w, r, fmt.Sprintf("/dashboard?%s", session.Values["query_params"]), 302)
 	} else {

+ 2 - 4
server/api/oauth_google_handler.go

@@ -95,11 +95,9 @@ func (app *App) HandleGoogleOAuthCallback(w http.ResponseWriter, r *http.Request
 	}
 
 	// send to segment
-	app.AnalyticsClient.Identify(analytics.CreateSegmentIdentifyUser(user))
+	app.analyticsClient.Identify(analytics.CreateSegmentIdentifyNewUser(user, true))
 
-	app.AnalyticsClient.Track(analytics.UserCreateTrack(&analytics.UserCreateTrackOpts{
-		UserScopedTrackOpts: analytics.GetUserScopedTrackOpts(user.ID),
-	}))
+	app.analyticsClient.Track(analytics.CreateSegmentNewUserTrack(user))
 
 	// log the user in
 	app.Logger.Info().Msgf("New user created: %d", user.ID)

+ 0 - 5
server/api/project_handler.go

@@ -7,7 +7,6 @@ import (
 
 	"github.com/go-chi/chi"
 	"github.com/porter-dev/porter/api/types"
-	"github.com/porter-dev/porter/internal/analytics"
 	"github.com/porter-dev/porter/internal/forms"
 	"github.com/porter-dev/porter/internal/models"
 )
@@ -73,10 +72,6 @@ func (app *App) HandleCreateProject(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	app.AnalyticsClient.Track(analytics.ProjectCreateTrack(&analytics.ProjectCreateTrackOpts{
-		ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, projModel.ID),
-	}))
-
 	app.Logger.Info().Msgf("New project created: %d", projModel.ID)
 
 	w.WriteHeader(http.StatusCreated)

+ 53 - 62
server/api/provision_handler.go

@@ -7,6 +7,8 @@ import (
 
 	"github.com/go-chi/chi"
 
+	"fmt"
+
 	"github.com/porter-dev/porter/internal/analytics"
 	"github.com/porter-dev/porter/internal/forms"
 	"github.com/porter-dev/porter/internal/kubernetes"
@@ -20,7 +22,6 @@ import (
 // container pod
 func (app *App) HandleProvisionTestInfra(w http.ResponseWriter, r *http.Request) {
 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-	userID, err := app.getUserIDFromRequest(r)
 
 	if err != nil || projID == 0 {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
@@ -45,8 +46,6 @@ func (app *App) HandleProvisionTestInfra(w http.ResponseWriter, r *http.Request)
 		return
 	}
 
-	infra.CreatedByUserID = userID
-
 	// handle write to the database
 	infra, err = app.Repo.Infra.CreateInfra(infra)
 
@@ -148,7 +147,6 @@ func (app *App) HandleDestroyTestInfra(w http.ResponseWriter, r *http.Request) {
 // HandleProvisionAWSECRInfra provisions a new aws ECR instance for a project
 func (app *App) HandleProvisionAWSECRInfra(w http.ResponseWriter, r *http.Request) {
 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-	userID, err := app.getUserIDFromRequest(r)
 
 	if err != nil || projID == 0 {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
@@ -179,8 +177,6 @@ func (app *App) HandleProvisionAWSECRInfra(w http.ResponseWriter, r *http.Reques
 		return
 	}
 
-	infra.CreatedByUserID = userID
-
 	// handle write to the database
 	infra, err = app.Repo.Infra.CreateInfra(infra)
 
@@ -223,14 +219,6 @@ func (app *App) HandleProvisionAWSECRInfra(w http.ResponseWriter, r *http.Reques
 
 	app.Logger.Info().Msgf("New aws ecr infra created: %d", infra.ID)
 
-	app.AnalyticsClient.Track(analytics.RegistryProvisioningStartTrack(
-		&analytics.RegistryProvisioningStartTrackOpts{
-			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
-			RegistryType:           models.InfraECR,
-			InfraID:                infra.ID,
-		},
-	))
-
 	w.WriteHeader(http.StatusCreated)
 
 	infraExt := infra.Externalize()
@@ -348,8 +336,6 @@ func (app *App) HandleProvisionAWSEKSInfra(w http.ResponseWriter, r *http.Reques
 		return
 	}
 
-	infra.CreatedByUserID = userID
-
 	// handle write to the database
 	infra, err = app.Repo.Infra.CreateInfra(infra)
 
@@ -392,12 +378,13 @@ func (app *App) HandleProvisionAWSEKSInfra(w http.ResponseWriter, r *http.Reques
 	}
 
 	app.Logger.Info().Msgf("New aws eks infra created: %d", infra.ID)
-
-	app.AnalyticsClient.Track(analytics.ClusterProvisioningStartTrack(
-		&analytics.ClusterProvisioningStartTrackOpts{
-			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
-			ClusterType:            models.InfraEKS,
-			InfraID:                infra.ID,
+	app.analyticsClient.Track(analytics.CreateSegmentNewClusterEvent(
+		&analytics.NewClusterEventOpts{
+			UserId:      fmt.Sprintf("%d", userID),
+			ProjId:      fmt.Sprintf("%d", infra.ProjectID),
+			ClusterName: form.EKSName,
+			ClusterType: "EKS",
+			EventType:   "provisioned",
 		},
 	))
 
@@ -415,7 +402,7 @@ func (app *App) HandleProvisionAWSEKSInfra(w http.ResponseWriter, r *http.Reques
 func (app *App) HandleDestroyAWSEKSInfra(w http.ResponseWriter, r *http.Request) {
 	// get path parameters
 	infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
-	// userID, err := app.getUserIDFromRequest(r)
+	userID, err := app.getUserIDFromRequest(r)
 
 	if err != nil {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
@@ -482,6 +469,15 @@ func (app *App) HandleDestroyAWSEKSInfra(w http.ResponseWriter, r *http.Request)
 	}
 
 	app.Logger.Info().Msgf("AWS EKS infra marked for destruction: %d", infra.ID)
+	app.analyticsClient.Track(analytics.CreateSegmentNewClusterEvent(
+		&analytics.NewClusterEventOpts{
+			UserId:      fmt.Sprintf("%d", userID),
+			ProjId:      fmt.Sprintf("%d", infra.ProjectID),
+			ClusterName: form.EKSName,
+			ClusterType: "EKS",
+			EventType:   "destroyed",
+		},
+	))
 
 	w.WriteHeader(http.StatusOK)
 }
@@ -489,7 +485,6 @@ func (app *App) HandleDestroyAWSEKSInfra(w http.ResponseWriter, r *http.Request)
 // HandleProvisionGCPGCRInfra enables GCR for a project
 func (app *App) HandleProvisionGCPGCRInfra(w http.ResponseWriter, r *http.Request) {
 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-	userID, err := app.getUserIDFromRequest(r)
 
 	if err != nil || projID == 0 {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
@@ -520,8 +515,6 @@ func (app *App) HandleProvisionGCPGCRInfra(w http.ResponseWriter, r *http.Reques
 		return
 	}
 
-	infra.CreatedByUserID = userID
-
 	// handle write to the database
 	infra, err = app.Repo.Infra.CreateInfra(infra)
 
@@ -563,14 +556,6 @@ func (app *App) HandleProvisionGCPGCRInfra(w http.ResponseWriter, r *http.Reques
 
 	app.Logger.Info().Msgf("New gcp gcr infra created: %d", infra.ID)
 
-	app.AnalyticsClient.Track(analytics.RegistryProvisioningStartTrack(
-		&analytics.RegistryProvisioningStartTrackOpts{
-			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
-			RegistryType:           models.InfraGCR,
-			InfraID:                infra.ID,
-		},
-	))
-
 	w.WriteHeader(http.StatusCreated)
 
 	infraExt := infra.Externalize()
@@ -615,8 +600,6 @@ func (app *App) HandleProvisionGCPGKEInfra(w http.ResponseWriter, r *http.Reques
 		return
 	}
 
-	infra.CreatedByUserID = userID
-
 	// handle write to the database
 	infra, err = app.Repo.Infra.CreateInfra(infra)
 
@@ -658,12 +641,13 @@ func (app *App) HandleProvisionGCPGKEInfra(w http.ResponseWriter, r *http.Reques
 	}
 
 	app.Logger.Info().Msgf("New gcp gke infra created: %d", infra.ID)
-
-	app.AnalyticsClient.Track(analytics.ClusterProvisioningStartTrack(
-		&analytics.ClusterProvisioningStartTrackOpts{
-			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
-			ClusterType:            models.InfraGKE,
-			InfraID:                infra.ID,
+	app.analyticsClient.Track(analytics.CreateSegmentNewClusterEvent(
+		&analytics.NewClusterEventOpts{
+			UserId:      fmt.Sprintf("%d", userID),
+			ProjId:      fmt.Sprintf("%d", infra.ProjectID),
+			ClusterName: form.GKEName,
+			ClusterType: "GKE",
+			EventType:   "provisioned",
 		},
 	))
 
@@ -681,7 +665,7 @@ func (app *App) HandleProvisionGCPGKEInfra(w http.ResponseWriter, r *http.Reques
 func (app *App) HandleDestroyGCPGKEInfra(w http.ResponseWriter, r *http.Request) {
 	// get path parameters
 	infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
-	// userID, err := app.getUserIDFromRequest(r)
+	userID, err := app.getUserIDFromRequest(r)
 
 	if err != nil {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
@@ -747,6 +731,15 @@ func (app *App) HandleDestroyGCPGKEInfra(w http.ResponseWriter, r *http.Request)
 	}
 
 	app.Logger.Info().Msgf("GCP GKE infra marked for destruction: %d", infra.ID)
+	app.analyticsClient.Track(analytics.CreateSegmentNewClusterEvent(
+		&analytics.NewClusterEventOpts{
+			UserId:      fmt.Sprintf("%d", userID),
+			ProjId:      fmt.Sprintf("%d", infra.ProjectID),
+			ClusterName: form.GKEName,
+			ClusterType: "GKE",
+			EventType:   "destroyed",
+		},
+	))
 
 	w.WriteHeader(http.StatusOK)
 }
@@ -798,7 +791,6 @@ func (app *App) HandleGetProvisioningLogs(w http.ResponseWriter, r *http.Request
 // HandleProvisionDODOCRInfra provisions a new digitalocean DOCR instance for a project
 func (app *App) HandleProvisionDODOCRInfra(w http.ResponseWriter, r *http.Request) {
 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-	userID, err := app.getUserIDFromRequest(r)
 
 	if err != nil || projID == 0 {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
@@ -829,8 +821,6 @@ func (app *App) HandleProvisionDODOCRInfra(w http.ResponseWriter, r *http.Reques
 		return
 	}
 
-	infra.CreatedByUserID = userID
-
 	// handle write to the database
 	infra, err = app.Repo.Infra.CreateInfra(infra)
 
@@ -875,14 +865,6 @@ func (app *App) HandleProvisionDODOCRInfra(w http.ResponseWriter, r *http.Reques
 
 	app.Logger.Info().Msgf("New do docr infra created: %d", infra.ID)
 
-	app.AnalyticsClient.Track(analytics.RegistryProvisioningStartTrack(
-		&analytics.RegistryProvisioningStartTrackOpts{
-			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
-			RegistryType:           models.InfraDOCR,
-			InfraID:                infra.ID,
-		},
-	))
-
 	w.WriteHeader(http.StatusCreated)
 
 	infraExt := infra.Externalize()
@@ -1002,8 +984,6 @@ func (app *App) HandleProvisionDODOKSInfra(w http.ResponseWriter, r *http.Reques
 		return
 	}
 
-	infra.CreatedByUserID = userID
-
 	// handle write to the database
 	infra, err = app.Repo.Infra.CreateInfra(infra)
 
@@ -1047,12 +1027,13 @@ func (app *App) HandleProvisionDODOKSInfra(w http.ResponseWriter, r *http.Reques
 	}
 
 	app.Logger.Info().Msgf("New do doks infra created: %d", infra.ID)
-
-	app.AnalyticsClient.Track(analytics.ClusterProvisioningStartTrack(
-		&analytics.ClusterProvisioningStartTrackOpts{
-			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
-			ClusterType:            models.InfraDOKS,
-			InfraID:                infra.ID,
+	app.analyticsClient.Track(analytics.CreateSegmentNewClusterEvent(
+		&analytics.NewClusterEventOpts{
+			UserId:      fmt.Sprintf("%d", userID),
+			ProjId:      fmt.Sprintf("%d", infra.ProjectID),
+			ClusterName: form.DOKSName,
+			ClusterType: "DOKS",
+			EventType:   "provisioned",
 		},
 	))
 
@@ -1070,6 +1051,7 @@ func (app *App) HandleProvisionDODOKSInfra(w http.ResponseWriter, r *http.Reques
 func (app *App) HandleDestroyDODOKSInfra(w http.ResponseWriter, r *http.Request) {
 	// get path parameters
 	infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
+	userID, err := app.getUserIDFromRequest(r)
 
 	if err != nil {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
@@ -1137,6 +1119,15 @@ func (app *App) HandleDestroyDODOKSInfra(w http.ResponseWriter, r *http.Request)
 	}
 
 	app.Logger.Info().Msgf("DO DOKS infra marked for destruction: %d", infra.ID)
+	app.analyticsClient.Track(analytics.CreateSegmentNewClusterEvent(
+		&analytics.NewClusterEventOpts{
+			UserId:      fmt.Sprintf("%d", userID),
+			ProjId:      fmt.Sprintf("%d", infra.ProjectID),
+			ClusterName: form.DOKSName,
+			ClusterType: "DOKS",
+			EventType:   "destroyed",
+		},
+	))
 
 	w.WriteHeader(http.StatusOK)
 }

+ 1 - 17
server/api/registry_handler.go

@@ -8,8 +8,8 @@ import (
 	"strings"
 	"time"
 
-	"github.com/porter-dev/porter/internal/analytics"
 	"github.com/porter-dev/porter/internal/oauth"
+
 	"github.com/porter-dev/porter/internal/registry"
 
 	"github.com/go-chi/chi"
@@ -22,21 +22,12 @@ import (
 // HandleCreateRegistry creates a new registry
 func (app *App) HandleCreateRegistry(w http.ResponseWriter, r *http.Request) {
 	projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
-	userID, err := app.getUserIDFromRequest(r)
-	flowID := oauth.CreateRandomState()
 
 	if err != nil || projID == 0 {
 		app.handleErrorFormDecoding(err, ErrProjectDecode, w)
 		return
 	}
 
-	app.AnalyticsClient.Track(analytics.RegistryConnectionStartTrack(
-		&analytics.RegistryConnectionStartTrackOpts{
-			ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
-			FlowID:                 flowID,
-		},
-	))
-
 	form := &forms.CreateRegistry{
 		ProjectID: uint(projID),
 	}
@@ -71,13 +62,6 @@ func (app *App) HandleCreateRegistry(w http.ResponseWriter, r *http.Request) {
 
 	app.Logger.Info().Msgf("New registry created: %d", registry.ID)
 
-	app.AnalyticsClient.Track(analytics.RegistryConnectionSuccessTrack(
-		&analytics.RegistryConnectionSuccessTrackOpts{
-			RegistryScopedTrackOpts: analytics.GetRegistryScopedTrackOpts(userID, uint(projID), registry.ID),
-			FlowID:                  flowID,
-		},
-	))
-
 	w.WriteHeader(http.StatusCreated)
 
 	regExt := registry.Externalize()

+ 3 - 14
server/api/release_handler.go

@@ -1059,7 +1059,8 @@ func (app *App) HandleUpgradeRelease(w http.ResponseWriter, r *http.Request) {
 		notifyOpts.Status = slack.StatusFailed
 		notifyOpts.Info = upgradeErr.Error()
 
-		notifier.Notify(notifyOpts)
+		slackErr := notifier.Notify(notifyOpts)
+		fmt.Println("SLACK ERROR IS", slackErr)
 
 		app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
 			Code:   ErrReleaseDeploy,
@@ -1315,19 +1316,7 @@ func (app *App) HandleReleaseDeployWebhook(w http.ResponseWriter, r *http.Reques
 
 	notifier.Notify(notifyOpts)
 
-	userID, _ := app.getUserIDFromRequest(r)
-
-	app.AnalyticsClient.Track(analytics.ApplicationDeploymentWebhookTrack(&analytics.ApplicationDeploymentWebhookTrackOpts{
-		ImageURI: fmt.Sprintf("%v", repository),
-		ApplicationScopedTrackOpts: analytics.GetApplicationScopedTrackOpts(
-			userID,
-			release.ProjectID,
-			release.ClusterID,
-			release.Name,
-			release.Namespace,
-			rel.Chart.Metadata.Name,
-		),
-	}))
+	app.analyticsClient.Track(analytics.CreateSegmentRedeployViaWebhookTrack("anonymous", repository.(string)))
 
 	w.WriteHeader(http.StatusOK)
 }

+ 2 - 5
server/api/user_handler.go

@@ -54,11 +54,8 @@ func (app *App) HandleCreateUser(w http.ResponseWriter, r *http.Request) {
 
 	if err == nil {
 		// send to segment
-		app.AnalyticsClient.Identify(analytics.CreateSegmentIdentifyUser(user))
-
-		app.AnalyticsClient.Track(analytics.UserCreateTrack(&analytics.UserCreateTrackOpts{
-			UserScopedTrackOpts: analytics.GetUserScopedTrackOpts(user.ID),
-		}))
+		app.analyticsClient.Identify(analytics.CreateSegmentIdentifyNewUser(user, false))
+		app.analyticsClient.Track(analytics.CreateSegmentNewUserTrack(user))
 
 		app.Logger.Info().Msgf("New user created: %d", user.ID)
 

+ 0 - 72
server/router/router.go

@@ -420,49 +420,6 @@ func New(a *api.App) *chi.Mux {
 				),
 			)
 
-			// /api/projects/{project_id}/events routes
-			r.Method(
-				"POST",
-				"/projects/{project_id}/clusters/{cluster_id}/events",
-				auth.DoesUserHaveProjectAccess(
-					auth.DoesUserHaveClusterAccess(
-						requestlog.NewHandler(a.HandleCreateEvent, l),
-						mw.URLParam,
-						mw.URLParam,
-					),
-					mw.URLParam,
-					mw.AdminAccess,
-				),
-			)
-
-			r.Method(
-				"GET",
-				"/projects/{project_id}/clusters/{cluster_id}/events",
-				auth.DoesUserHaveProjectAccess(
-					auth.DoesUserHaveClusterAccess(
-						requestlog.NewHandler(a.HandleListEvents, l),
-						mw.URLParam,
-						mw.URLParam,
-					),
-					mw.URLParam,
-					mw.AdminAccess,
-				),
-			)
-
-			r.Method(
-				"GET",
-				"/projects/{project_id}/clusters/{cluster_id}/events/{event_id}",
-				auth.DoesUserHaveProjectAccess(
-					auth.DoesUserHaveClusterAccess(
-						requestlog.NewHandler(a.HandleGetEvent, l),
-						mw.URLParam,
-						mw.URLParam,
-					),
-					mw.URLParam,
-					mw.AdminAccess,
-				),
-			)
-
 			// /api/projects/{project_id}/invites routes
 			r.Method(
 				"POST",
@@ -1367,35 +1324,6 @@ func New(a *api.App) *chi.Mux {
 				),
 			)
 
-			// api/projects/{project_id}/agent routes
-			r.Method(
-				"POST",
-				"/projects/{project_id}/agent/deploy",
-				auth.DoesUserHaveProjectAccess(
-					auth.DoesUserHaveClusterAccess(
-						requestlog.NewHandler(a.HandleDeployAgent, l),
-						mw.URLParam,
-						mw.QueryParam,
-					),
-					mw.URLParam,
-					mw.WriteAccess,
-				),
-			)
-
-			r.Method(
-				"GET",
-				"/projects/{project_id}/agent/detect",
-				auth.DoesUserHaveProjectAccess(
-					auth.DoesUserHaveClusterAccess(
-						requestlog.NewHandler(a.HandleDetectPorterAgentInstalled, l),
-						mw.URLParam,
-						mw.QueryParam,
-					),
-					mw.URLParam,
-					mw.ReadAccess,
-				),
-			)
-
 			// /api/projects/{project_id}/k8s routes
 			r.Method(
 				"GET",