# Sandstorm - Personal Cloud Sandbox
# Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

@0xa4e001d4cbcf33fa;

$import "/capnp/c++.capnp".namespace("sandstorm");

using Util = import "util.capnp";
using Identity = import "identity.capnp";

struct ActivityEvent {
  # Describes an event in a grain's activity feed / log.
  #
  # Call SessionContext.activity() to post new activity. The activity is attributed to the user
  # whose SessionContext was used.

  path @0 :Text;
  # Path (as in, URL) within the grain where the user can see this activity. Users inspecting the
  # event will be linked to this location. Visiting this path implicitly marks the event as "read".
  #
  # This should NOT include a leading '/'. (So, an empty string -- the default -- goes to the grain
  # root).

  thread @4 :ThreadInfo;
  # If this event is a member of a "thread", information about that thread. For example, in an
  # issue tracker app, all comments on an issue would be part of the same "thread". Threads are
  # important for deciding who gets notified and for grouping those notifications: a user might
  # subscribe to a particular thread, and e.g. email notifications related to a thread may be
  # designed to appear as a single email thread.

  struct ThreadInfo {
    path @0 :Text;
    # Like ActivityEvent.path, but identifies the path to the thread in general. For subscription
    # purposes, a thread must be uniquely identified by its path.

    title @1 :Util.LocalizedText;
    # The title of the thread, e.g. for use in an email subject line. Note that if a thread's title
    # changes, it may cause email notifications related to the therad to form a new thread, since
    # email clients commonly create email threads based on subject line.
  }

  notification @1 :NotificationDisplayInfo;
  # Optional metadata used to render a notification about this event. This metadata is not stored
  # in the activity log long-term. It is used e.g. to construct a notification email message or
  # to display in the notification "bell" menu (discarded once the notification is dismissed).
  #
  # It is OK to leave this null for simple events, especially events that don't by default send
  # notifications.

  type @2 :UInt16;
  # Event type; index into UiView.ViewInfo.eventTypes. Users are able to choose which types of
  # events should notify them.

  users @3 :List(User);
  # List of user identities connected to this event.

  struct User {
    # Information about a specific user's relationship with this event. At least one of the fields
    # other than `identityId` should be non-default, otherwise listing the user has no purpose.

    identity @0 :Identity.Identity;

    mentioned @1 :Bool;
    # This user is explicitly "mentioned" by this event, e.g. like an @-mention on Twitter or
    # GitHub. In the activity log, the event may explicitly show who was mentioned, and mentioned
    # users may be notified even if they are not explicitly subscribed to the event.
    #
    # Note that if you want a user to be notified but they *aren't* actually "mentioned" by the
    # event, you may want to use `subscribed`, below, instead. As a rule of thumb, think about
    # how to complete this sentence: "You received this notification because _______" If the blank
    # should say "you were mentioned", then set `mentioned = true`. If it would say "you are
    # subscribed to this thread" (or something like that), set `subscribed = true`.

    subscribed @3 :Bool;
    # Set true if the application manages a concept of "subscriptions" internally (rather than
    # letting Sandstorm do it), and that according to this internal computation, the user is
    # "subscribed" to this event. The effect of this is that the user will be notified of the
    # event even though it doesn't specifically "mention" them. The user may be informed that they
    # are being notified because they are subscribed.
    #
    # Generally, an app should *not* use this field if it uses `autoSubscribeToThread`,
    # `autoSubscribeToGrain`, or the Sandstorm APIs for notification subscriptions. Only use this
    # field if your app is implementing its own notion of subscriptions.

    canView @2 :Bool;
    # This user can view this event *even if* they do not meet the `requiredPermission` in the
    # type definition. (However, if the user has no access to the grain at all, they still will
    # not see the event.) This flag is useful when the app is doing its own internal access control
    # rather than relying strictly on Sandstorm permissions.
  }
}

struct ActivityTypeDef {
  name @0 :Text;
  # Name of the type, used as an identifier for the type in cases where string names
  # are preferred. These names will never be used in Cap'n Proto interfaces, but could show up in
  # HTTP or JSON translations.
  #
  # The name must be a valid identifier (alphanumerics only, starting with a letter) and must be
  # unique among all types defined for a particular UiView.

  verbPhrase @1 :Util.LocalizedText;
  # Text of a verb phrase describing what the acting user did, e.g.:
  # * "edited document"
  # * "created new comment"
  # * "replied to comment"
  #
  # The activity log, when displayed, may contain text like:
  #
  #     Kenton Varda - 3 hours ago
  #     * edited document x13
  #     * created new comment
  #     * replied to comment x2
  #     Jade Wang - 2 hours ago
  #     * replied to comment x3
  #     * edited document x5

  description @2 :Util.LocalizedText;
  # Prose describing what this activity type means, suitable for a tool tip or similar help text.
  # Optional.

  requiredPermission :union {
    # Who is allowed to observe events of this type?

    everyone @3 :Void;
    # All users who have any access to this grain are allowed to observe this event.

    permissionIndex @4 :UInt16;
    # Users who have the given permission are allowed to observe this event.

    explicitList @5 :Void;
    # Only users explicitly listed.
  }

  obsolete @6 :Bool = false;
  # If true, this activity type was relevant in a previous version of the application but is no
  # longer used. The activity type will be hidden from the notification settings (and any events
  # of this type will not generate notifications).

  # The options below are hints controlling how users are notified of events. Note that these are
  # only hints; a user can potentially override whether or not a particular event causes a
  # notification through a variety of mechanisms. However, these hints are designed to be good
  # defaults.

  notifySubscribers @7 :Bool;
  # Should subscribers to this event (including subscribers to the event's thread, if any, and
  # subscribers to the event's grain) receive a notification of this event, by default?
  #
  # Note that when the user explicitly subscribes through the UI, they will have the opportunity
  # to choose exactly which event types they want to produce notifications. Moreover, when an app
  # provides a "subscribe" button in its own UI, and the user clicks it, the app can specify
  # different defaults that should apply to that button.
  #
  # Therefore, the `notifySubscribers` bit primarily serves two purposes:
  # - It applies to auto-subscriptions as created due to the `autoSubscribeToThread` or
  #   `autoSubscribeToGrain` bits (below).
  # - It applies when an update to the app defines a new type of event. Users who are subscribed
  #   to other kinds of notifications will be subscribed to the new notification type if and only
  #   if it has `notifySubscribers = true`.

  autoSubscribeToThread @8 :Bool;
  # Should the author of this event automatically become subscribed to the thread of which it is
  # a part? (If the event has no threadPath, this option has no effect.)
  #
  # Such an automatic subscription specifically subscribes the user to events which have
  # `notifySubscribers = true` (above).

  autoSubscribeToGrain @9 :Bool;
  # Should the author of this event automatically become subscribed to the grain?
  #
  # Such an automatic subscription specifically subscribes the user to events which have
  # `notifySubscribers = true` (above).

  suppressUnread @10 :Bool;
  # If true, this kind of activity does not cause the grain to be marked "unread". This is useful
  # for activities that should be logged but don't need attention.
}

struct NotificationDisplayInfo {
  caption @0 :Util.LocalizedText;
  # Text to display inside the notification box.

  # TODO(someday): "Body" containing extended text, for the body of an email or perhaps for display
  #   in the bell menu after the user clicks on the notification (Google+ style).
  # TODO(someday): Support notifications that can receive text replies. The replies are delivered
  #   to a provided capability. When notifications are delivered via email, Sandstorm can
  #   automatically support email replies. When notifications are delivered via the bell menu,
  #   Sandstorm can render an inline reply textarea (like Google+ notifications).
  # TODO(someday): Support rich interactive notifications, e.g. the ability to play/pause music
  #   via buttons.
}

interface NotificationTarget @0xf0f87337d73020f0 {
  # Represents a destination for notifications; usually, a user.
  #
  # TODO(someday): Expand on this and move it into `grain.capnp` when notifications are
  #   fully-implemented.

  addOngoing @0 (displayInfo :NotificationDisplayInfo, notification :OngoingNotification)
             -> (handle :Util.Handle);
  # Sends an ongoing notification to the notification target. `notification` must be persistent.
  # The notification is removed when the returned `handle` is dropped. The handle is persistent.
}

interface OngoingNotification @0xfe851ddbb88940cd {
  # Callback interface passed to the platform when registering a persistent notification.

  cancel @0 ();
  # Informs the notification creator that the user has requested cancellation of the task
  # underlying this notification.
  #
  # In the case of a `SandstormApi.stayAwake()` notification, after `cancel()` is called, the app
  # will no longer be held awake, so should prepare for shutdown.
  #
  # TODO(someday): We could allow the app to return some text to display to the user asking if
  #   they really want to shut down.
}
