Unverified Commit e4a46cec authored by Kevin Lyda's avatar Kevin Lyda
Browse files

Cleanup db in prep for storage module

parent 56ef5b0f
Loading
Loading
Loading
Loading
+25 −3
Original line number Diff line number Diff line
@@ -106,11 +106,35 @@ func split(line string) []string {
	return words
}

// PrefixMatch searches for a command in a list of possible commands.
func PrefixMatch(command string, commands []string) (string, error) {
	cmd := strings.ToUpper(command)
	possibles := []string{}
	for i := range commands {
		if strings.HasPrefix(cmd, commands[i]) {
			possibles = append(possibles, commands[i])
		}
	}
	switch len(possibles) {
	case 0:
		return "", fmt.Errorf("Unknown command '%s'", command)
	case 1:
		return possibles[0], nil
	default:
		return "", fmt.Errorf("Ambiguous command '%s' (matches %s)",
			command, strings.Join(possibles, ", "))
	}
}

// ParseAndRun parses a command line and runs the command.
func (c Commands) ParseAndRun(line string) error {
	// Split into words.
	words := split(line)

	return c.run(words)
}

func (c Commands) run(words []string) error {
	// Find the command.
	wordup := strings.ToUpper(words[0])
	cmd, ok := c[wordup]
@@ -141,9 +165,7 @@ func (c Commands) ParseAndRun(line string) error {
			fmt.Printf("ERROR: missing subcommand for %s.\n", wordup)
			return nil
		}
		// TODO: quoting is probably an issue here - break ParseAndRun into ParseAndRun + Run.
		newline := strings.Join(words[1:], " ")
		return cmd.Commands.ParseAndRun(newline)
		return cmd.Commands.run(words[1:])
	}

	if cmd.Action == nil {
+30 −23
Original line number Diff line number Diff line
CREATE TABLE users (
  login       VARCHAR(12)  NOT NULL PRIMARY KEY,
  name        VARCHAR(53)  NOT NULL,
  admin       INT          DEFAULT 0,
  disabled    INT          DEFAULT 0,
  admin       INT          DEFAULT 0 NOT NULL,
  moderator   INT          DEFAULT 0 NOT NULL,
  disabled    INT          DEFAULT 0 NOT NULL,
  last_login  TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
  create_at   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
  update_at   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL
@@ -34,16 +35,15 @@ END;

CREATE TABLE folders (
  name        VARCHAR(25)  NOT NULL PRIMARY KEY,
  always      INT          DEFAULT 0,
  brief       INT          DEFAULT 0,
  description VARCHAR(53)  NOT NULL,
  notify      INT          DEFAULT 0,
  owner       VARCHAR(25)  REFERENCES users(login) ON UPDATE CASCADE,
  readnew     INT          DEFAULT 0,
  shownew     INT          DEFAULT 0,
  system      INT          DEFAULT 0,
  expire      INT          DEFAULT 14,
  visibility  TEXT         DEFAULT 'public',
  always      INT          DEFAULT 0 NOT NULL,
  brief       INT          DEFAULT 0 NOT NULL,
  description VARCHAR(53)  DEFAULT 0 NOT NULL,
  notify      INT          DEFAULT 0 NOT NULL,
  readnew     INT          DEFAULT 0 NOT NULL,
  shownew     INT          DEFAULT 0 NOT NULL,
  system      INT          DEFAULT 0 NOT NULL,
  expire      INT          DEFAULT 14 NOT NULL,
  visibility  TEXT         DEFAULT 'public' NOT NULL,
  create_at   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
  update_at   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL
) WITHOUT ROWID;
@@ -87,7 +87,7 @@ END;
INSERT INTO folders (name, description, system, shownew, owner)
       VALUES ('GENERAL', 'Default general bulletin folder.', 1, 1, 'SYSTEM');

CREATE TABLE co_owners (
CREATE TABLE owners (
  folder      VARCHAR(25)  REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE,
  owner       VARCHAR(25)  REFERENCES users(login) ON UPDATE CASCADE,
  create_at   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
@@ -95,11 +95,11 @@ CREATE TABLE co_owners (
  PRIMARY KEY (folder, owner)
) WITHOUT ROWID;

CREATE TRIGGER co_owners_after_update_update_at
  AFTER UPDATE ON co_owners FOR EACH ROW
CREATE TRIGGER owners_after_update_update_at
  AFTER UPDATE ON owners FOR EACH ROW
    WHEN NEW.update_at = OLD.update_at    --- avoid infinite loop
BEGIN
  UPDATE co_owners SET update_at=CURRENT_TIMESTAMP WHERE folder=NEW.folder AND owner=NEW.owner;
  UPDATE owners SET update_at=CURRENT_TIMESTAMP WHERE folder=NEW.folder AND owner=NEW.owner;
END;

CREATE TABLE messages (
@@ -108,8 +108,8 @@ CREATE TABLE messages (
  author      VARCHAR(25)  REFERENCES users(login) ON UPDATE CASCADE,
  subject     VARCHAR(53)  NOT NULL,
  message     TEXT         NOT NULL,
  permanent   INT          DEFAULT 0,
  shutdown    INT          DEFAULT 0,
  permanent   INT          DEFAULT 0 NOT NULL,
  shutdown    INT          DEFAULT 0 NOT NULL,
  expiration  TIMESTAMP    NOT NULL,
  create_at   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
  update_at   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
@@ -118,7 +118,7 @@ CREATE TABLE messages (
CREATE INDEX messages_idx_shutdown ON messages(shutdown);
CREATE INDEX messages_idx_expiration ON messages(expiration);

CREATE TABLE read (
CREATE TABLE seen (
  login       VARCHAR(25) REFERENCES users(login) ON DELETE CASCADE ON UPDATE CASCADE,
  folder      VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE,
  msgid       INT,
@@ -142,13 +142,20 @@ CREATE TABLE mark (
    ON UPDATE CASCADE
) WITHOUT ROWID;

CREATE TABLE access (
  login       VARCHAR(25) REFERENCES users(login) ON DELETE CASCADE ON UPDATE CASCADE,
  folder      VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE,
  PRIMARY KEY (login, folder),
) WITHOUT ROWID;

--- TODO: The following is incomplete:
--- User configs.
CREATE TABLE config (
  login       VARCHAR(25) REFERENCES users(login) ON DELETE CASCADE ON UPDATE CASCADE,
  folder      VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE,
  always      INT NOT NULL,
  always      INT     NOT NULL DEFAULT 0,
  alert       INT     NOT NULL DEFAULT 0,  --- 0=no, 1=brief, 2=readnew
  always      INT     NOT NULL
) WITHOUT ROWID;

--- System configs.
+22 −60
Original line number Diff line number Diff line
@@ -1439,16 +1439,22 @@ to see what is presently set. This is a privileged command.

The parameters are one or  more  privileges  separated  by  commas.   To
remove  a privilege, specify the privilege preceeded by "NO".  If /ID is
specified, the parameters are rights identifiers.`,
				Flags: dclish.Flags{
					"/ID": {
						Description: `/[NO]ID
specified, the parameters are rights identifiers.

  If specified,  then the  rights identifier which  is specified  as the
  parameter will allow  users holding that rights  identifier to execute
  privileged commands. If /NOID is specified, the identifier is removed.`,
					},
				},
For the reimplementation this is used to manage users.  The following parameters
are available.

  Format:
	  SET PRIVILEGES CREATE login
	  SET PRIVILEGES DELETE login
	  SET PRIVILEGES SSH [login]
	  SET PRIVILEGES [NO]ADMIN login
	  SET PRIVILEGES [NO]MOD login [folder]
	  SET PRIVILEGES ENABLE login
	  SET PRIVILEGES DISABLE login`,
				MinArgs: 1,
				MaxArgs: 3,
				Action:  ActionSetPrivileges,
			},
			"PROMPT_EXPIRE": {
				Description: `Specifies  that a  user will  be prompted  for an  expiration date  when
@@ -1492,17 +1498,8 @@ the EXIT command will cause you to skip to those folders. (See HELP SET
SYSTEM for a description of a SYSTEM folder).`,
				Flags: dclish.Flags{
					"/ALL": {
						Description: `  Specifies that the SET [NO]READNEW option is the default for all users
  for  the  specified  folder.  This  is  a  privileged  qualifier.  The
  difference  between this  and /DEFAULT  is that  the latter  will only
  apply  to  new  users  (i.e.  any  users  which  have  never  executed
  BULLETIN).`,
					},
					"/DEFAULT": {
						Description: `  Specifies that the [NO]READNEW option is the default for the specified
  folder. This is a privileged qualifier.  It will only affect brand new
  users (or  those that have  never logged in).  Use /ALL to  modify all
  users.`,
						Description: `  Specifies that the SET READNEW option is the default for all users for
  the specified folder.  This is a privileged  qualifier.`,
					},
					"/PERMANENT": {
						Description: `/[NO]PERMANENT
@@ -1515,30 +1512,11 @@ SYSTEM for a description of a SYSTEM folder).`,
			"NOREADNEW": {
				Description: `Turns off READNEW.
  Format:
    SET NOREADNEW

NOTE:  If  you  have several folders with READNEW enabled, each folder's
messages will be displayed separately.  However, if you EXIT the READNEW
mode before all the folders have been displayed, you will not be alerted
of the new messages in the undisplayed folders the next time you  login.
However,  if  you enter BULLETIN, you will be told that new messages are
present in those other folders.  Also, it is not possible  to  EXIT  the
READNEW mode if there are SYSTEM folders which have new messages. Typing
the EXIT command will cause you to skip to those folders.  (See HELP SET
SYSTEM for a description of a SYSTEM folder).`,
    SET NOREADNEW`,
				Flags: dclish.Flags{
					"/ALL": {
						Description: `  Specifies that the SET [NO]READNEW option is the default for all users
  for  the  specified  folder.  This  is  a  privileged  qualifier.  The
  difference  between this  and /DEFAULT  is that  the latter  will only
  apply  to  new  users  (i.e.  any  users  which  have  never  executed
  BULLETIN).`,
					},
					"/DEFAULT": {
						Description: `  Specifies that the [NO]READNEW option is the default for the specified
  folder. This is a privileged qualifier.  It will only affect brand new
  users (or  those that have  never logged in).  Use /ALL to  modify all
  users.`,
						Description: `  Specifies that the  SET NOREADNEW option is the default  for all users
  for  the  specified  folder.  This  is  a  privileged  qualifier.`,
					},
					"/FOLDER": {
						Description: `/FOLDER=foldername
@@ -1564,15 +1542,8 @@ In order to apply this to a specific folder, first select the folder
				Flags: dclish.Flags{
					"/ALL": {
						Description: `  Specifies that the SET SHOWNEW option is the default for all users for
  the specified folder.  This is a privileged  qualifier. The difference
  between this  and /DEFAULT is that  the latter will only  apply to new
  users (i.e. any users which have never executed BULLETIN).`,
  the specified folder.  This is a privileged  qualifier.`,
					},
					"/DEFAULT": {
						Description: `  Specifies that  the SHOWNEW  option is the  default for  the specified
  folder. This is a privileged qualifier.  It will only affect brand new
  users (or  those that have  never logged in).  Use /ALL to  modify all
  users.`},
					"/PERMANENT": {
						Description: `/[NO]PERMANENT

@@ -1590,16 +1561,7 @@ In order to apply this to a specific folder, first select the folder
				Flags: dclish.Flags{
					"/ALL": {
						Description: `  Specifies that the  SET NOSHOWNEW option is the default  for all users
  for  the  specified  folder.  This  is  a  privileged  qualifier.  The
  difference  between this  and /DEFAULT  is that  the latter  will only
  apply  to  new  users  (i.e.  any  users  which  have  never  executed
  BULLETIN).`,
					},
					"/DEFAULT": {
						Description: `  Specifies that the  NOSHOWNEW option is the default  for the specified
  folder. This is a privileged qualifier.  It will only affect brand new
  users (or  those that have  never logged in).  Use /ALL to  modify all
  users.`,
  for  the  specified  folder.  This  is  a  privileged  qualifier.`,
					},
					"/FOLDER": {
						Description: `/FOLDER=foldername
+32 −2
Original line number Diff line number Diff line
@@ -89,8 +89,38 @@ func ActionSetNonotify(_ *dclish.Command) error {
}

// ActionSetPrivileges handles the `SET PRIVILEGES` command.
func ActionSetPrivileges(_ *dclish.Command) error {
	fmt.Println("TODO: implement ActionSetPrivileges.")
func ActionSetPrivileges(cmd *dclish.Command) error {
	// TODO: OK, need a better parser.
	switch cmd.Args[0] {
	case "CREATE":
		if len(cmd.Args) != 2 {
			fmt.Println("ERROR: Must pass single login.")
			return nil
		}
		fmt.Println("TODO: Create user creation routine - see repl/repl.go.")
	case "DELETE":
		if len(cmd.Args) != 2 {
			fmt.Println("ERROR: Must pass single login.")
			return nil
		}
		fmt.Println("TODO: Create user delete routine - see repl/repl.go.")
	case "SSH":
		fmt.Println("TODO: Create ssh routine.")
	case "ADMIN":
		fmt.Println("TODO: Create an admin bit set/unset routine.")
	case "NOADMIN":
		fmt.Println("TODO: Create an admin bit set/unset routine.")
	case "MOD":
		fmt.Println("TODO: Create a mod bit set/unset routine.")
	case "NOMOD":
		fmt.Println("TODO: Create a mod bit set/unset routine.")
	case "ENABLE":
		fmt.Println("TODO: Create a disable bit set/unset routine.")
	case "DISABLE":
		fmt.Println("TODO: Create a disable bit set/unset routine.")
	default:
		fmt.Println("ERROR: Command not understood.")
	}
	return nil
}