commit cff8c0ee1d3d8e404dc480392e5e6c6e8186949e
Author: Phorge Migration <migration@localhost>
Date: Tue, 21 Jul 2026 18:24:31 +0200
Archive issues/PRs export for Nordgedanken/Morpheusv2
Diffstat:
28 files changed, 3901 insertions(+), 0 deletions(-)
diff --git a/issues/5.json b/issues/5.json
@@ -0,0 +1,16 @@
+{
+ "number": 5,
+ "title": "Use migrate for the DB tables to make sure we wont run in non true errors because I changed a DB table",
+ "state": "open",
+ "author": "MTRNord",
+ "created_at": "2018-05-05T22:39:35Z",
+ "closed_at": null,
+ "labels": [
+ "enhancement"
+ ],
+ "assignees": [
+ "MTRNord"
+ ],
+ "body": "https://github.com/mattes/migrate",
+ "comments": []
+}
diff --git a/issues/5.md b/issues/5.md
@@ -0,0 +1,12 @@
+# #5 Use migrate for the DB tables to make sure we wont run in non true errors because I changed a DB table
+
+- **State:** open
+- **Author:** @MTRNord
+- **Created:** 2018-05-05T22:39:35Z
+- **Labels:** enhancement
+- **Assignees:** @MTRNord
+
+---
+
+https://github.com/mattes/migrate
+
diff --git a/issues/9.json b/issues/9.json
@@ -0,0 +1,18 @@
+{
+ "number": 9,
+ "title": "Make sure we use qimage instead qpixmap ",
+ "state": "closed",
+ "author": "MTRNord",
+ "created_at": "2018-05-06T06:42:59Z",
+ "closed_at": "2018-05-09T19:24:19Z",
+ "labels": [],
+ "assignees": [],
+ "body": "",
+ "comments": [
+ {
+ "author": "MTRNord",
+ "created_at": "2018-05-06T06:44:23Z",
+ "body": "https://stackoverflow.com/a/4474570/4929236"
+ }
+ ]
+}
diff --git a/issues/9.md b/issues/9.md
@@ -0,0 +1,18 @@
+# #9 Make sure we use qimage instead qpixmap
+
+- **State:** closed
+- **Author:** @MTRNord
+- **Created:** 2018-05-06T06:42:59Z
+- **Closed:** 2018-05-09T19:24:19Z
+
+---
+
+_No description._
+
+
+## Comments
+
+### @MTRNord — 2018-05-06T06:44:23Z
+
+https://stackoverflow.com/a/4474570/4929236
+
diff --git a/pulls/1.diff b/pulls/1.diff
@@ -0,0 +1,156 @@
+diff --git a/.circleci/config.yml b/.circleci/config.yml
+index 4fee27f..5f9a38f 100644
+--- a/.circleci/config.yml
++++ b/.circleci/config.yml
+@@ -41,7 +41,7 @@ jobs:
+ - run:
+ name: Run Build
+ working_directory: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/
+- command: $GOPATH/bin/qtdeploy build linux
++ command: /home/user/work/bin/qtdeploy build desktop
+ - run:
+ name: Prepare Deb Generating
+ working_directory: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/
+@@ -86,7 +86,7 @@ jobs:
+ - run:
+ name: Run Build
+ working_directory: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/
+- command: $GOPATH/bin/qtdeploy build windows
++ command: /home/user/work/bin/qtdeploy build windows
+ - store_artifacts:
+ path: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/deploy/windows/Morpheusv2.exe
+ destination: Morpheusv2.exe
+diff --git a/Gopkg.lock b/Gopkg.lock
+index 13077c2..ec45e23 100644
+--- a/Gopkg.lock
++++ b/Gopkg.lock
+@@ -25,15 +25,9 @@
+ revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
+ version = "v1.0.1"
+
+-[[projects]]
+- branch = "master"
+- name = "github.com/therecipe/qt"
+- packages = [".","core","gui","widgets"]
+- revision = "7038382d6c7bb5fd3957df56bbedf8ec4ca6b67c"
+-
+ [solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+- inputs-digest = "a82e2ac4eccca051143202632fee6ebf07b015e82f3d04c4bc426be93aab708b"
++ inputs-digest = "9eae52af7d8c49e9a27a1863ba05582acb167fd5a5ce5bf23b6eb9288a20d0c2"
+ solver-name = "gps-cdcl"
+ solver-version = 1
+diff --git a/Gopkg.toml b/Gopkg.toml
+index a975b22..b1ccb25 100644
+--- a/Gopkg.toml
++++ b/Gopkg.toml
+@@ -21,10 +21,8 @@
+ # version = "2.4.0"
+
+
+-[[constraint]]
+- branch = "master"
+- name = "github.com/shibukawa/configdir"
++ignored = ["github.com/therecipe/qt/*"]
+
+ [[constraint]]
+ branch = "master"
+- name = "github.com/therecipe/qt"
++ name = "github.com/shibukawa/configdir"
+\ No newline at end of file
+diff --git a/cmd/root.go b/cmd/root.go
+index 3374e09..61a0ac4 100644
+--- a/cmd/root.go
++++ b/cmd/root.go
+@@ -22,8 +22,6 @@ import (
+ "github.com/spf13/cobra"
+ )
+
+-var cfgFile string
+-
+ // rootCmd represents the base command when called without any subcommands
+ var rootCmd = &cobra.Command{
+ Use: "Morpheusv2",
+@@ -48,5 +46,4 @@ func Execute() {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+- os.Exit(0)
+ }
+diff --git a/deb.json b/deb.json
+index 767176a..f710e5e 100644
+--- a/deb.json
++++ b/deb.json
+@@ -1,7 +1,7 @@
+ {
+ "name": "Morpheusv2",
+ "maintainer": "MTRNord <info@nordgedanken.de>",
+- "version": "0.0.1",
++ "version": "0.1.0",
+ "arch": "amd64",
+ "files": [
+ {
+@@ -50,7 +50,7 @@
+ "description":"A Matrix client written in Go-QT ",
+ "generic-name":"Matrix Client",
+ "exec":"/usr/bin/Morpheusv2.sh",
+- "icon":"qml/resources/logos/MorpheusBig.png",
++ "icon":"pkg/qml/resources/logos/MorpheusBig.png",
+ "type":"Application",
+ "keywords":"matrix;Morpheusv2",
+ "startup-notify": false,
+diff --git a/linter.json b/linter.json
+new file mode 100644
+index 0000000..2b2b1f4
+--- /dev/null
++++ b/linter.json
+@@ -0,0 +1,22 @@
++{
++ "Vendor": true,
++ "Cyclo": 12,
++ "Deadline": "5m",
++ "Enable": [
++ "vetshadow",
++ "deadcode",
++ "gocyclo",
++ "golint",
++ "varcheck",
++ "structcheck",
++ "ineffassign",
++ "gas",
++ "misspell",
++ "unparam",
++ "errcheck",
++ "vet",
++ "megacheck",
++ "goconst",
++ "maligned"
++ ]
++}
+\ No newline at end of file
+diff --git a/pkg/app/main.go b/pkg/app/main.go
+index 5caabde..43d28a6 100644
+--- a/pkg/app/main.go
++++ b/pkg/app/main.go
+@@ -24,6 +24,7 @@ import (
+ "path/filepath"
+ )
+
++// Start prepares the Main QT Window and opens it
+ func Start(args []string) error {
+ log.Println("Starting Morpheus v2")
+
+diff --git a/pkg/mainThreadHelper.go b/pkg/mainThreadHelper.go
+index 32b4d1a..4311a21 100644
+--- a/pkg/mainThreadHelper.go
++++ b/pkg/mainThreadHelper.go
+@@ -27,7 +27,7 @@ func Main() {
+ // queue of work to run in main thread.
+ var mainfunc = make(chan func())
+
+-// do runs f on the main thread.
++// Do runs f on the main thread.
+ func Do(f func()) {
+ done := make(chan bool, 1)
+ mainfunc <- func() {
diff --git a/pulls/1.json b/pulls/1.json
@@ -0,0 +1,22 @@
+{
+ "number": 1,
+ "title": "Fix CI building",
+ "state": "merged",
+ "diff_file": "1.diff",
+ "author": "MTRNord",
+ "created_at": "2018-05-01T16:21:48Z",
+ "closed_at": "2018-05-01T16:33:41Z",
+ "merged_at": "2018-05-01T16:33:41Z",
+ "base_ref": "master",
+ "head_ref": "develop",
+ "labels": [
+ "enhancement"
+ ],
+ "assignees": [
+ "MTRNord"
+ ],
+ "requested_reviewers": [],
+ "body": "",
+ "comments": [],
+ "review_comments": []
+}
diff --git a/pulls/1.md b/pulls/1.md
@@ -0,0 +1,15 @@
+# PR #1 Fix CI building
+
+- **Status:** merged
+- **Author:** @MTRNord
+- **Created:** 2018-05-01T16:21:48Z
+- **Branch:** develop → master
+- **Merged:** 2018-05-01T16:33:41Z
+- **Labels:** enhancement
+- **Assignees:** @MTRNord
+- **Diff:** [1.diff](./1.diff)
+
+---
+
+_No description._
+
diff --git a/pulls/10.diff b/pulls/10.diff
@@ -0,0 +1,22 @@
+diff --git a/README.md b/README.md
+index efb62e7..e05ff01 100644
+--- a/README.md
++++ b/README.md
+@@ -1,5 +1,6 @@
+ # Morpheus v2
+ [](https://circleci.com/gh/Nordgedanken/Morpheusv2)
++[](https://app.fossa.io/projects/git%2Bgithub.com%2FNordgedanken%2FMorpheusv2?ref=badge_shield)
+
+ []()
+
+@@ -35,5 +36,8 @@ We use [SemVer](http://semver.org/) for versioning. For the versions available,
+ ## License
+ This project is licensed under the Apache 2.0 License - see the [LICENSE](LICENSE) file for details
+
++
++[](https://app.fossa.io/projects/git%2Bgithub.com%2FNordgedanken%2FMorpheusv2?ref=badge_large)
++
+ ## Acknowledgments
+-* Inspired by [nheko](http://github.com/mujx/nheko)
++* Inspired by [nheko](http://github.com/mujx/nheko)
+\ No newline at end of file
diff --git a/pulls/10.json b/pulls/10.json
@@ -0,0 +1,18 @@
+{
+ "number": 10,
+ "title": "Add license scan report and status",
+ "state": "open",
+ "diff_file": "10.diff",
+ "author": "fossabot",
+ "created_at": "2018-05-12T22:37:04Z",
+ "closed_at": null,
+ "merged_at": null,
+ "base_ref": "master",
+ "head_ref": "master",
+ "labels": [],
+ "assignees": [],
+ "requested_reviewers": [],
+ "body": "Your FOSSA integration was successful! Attached in this PR is a badge and license report to track scan status in your README.\n\nBelow are docs for integrating FOSSA license checks into your CI:\n\n- [CircleCI](https://docs.fossa.io/docs/circleci)\n- [TravisCI](https://docs.fossa.io/docs/travisci)\n- [Jenkins](https://github.com/fossas/fossa-jenkins-plugin)\n- [Other](https://github.com/fossas/fossa-cli)",
+ "comments": [],
+ "review_comments": []
+}
diff --git a/pulls/10.md b/pulls/10.md
@@ -0,0 +1,19 @@
+# PR #10 Add license scan report and status
+
+- **Status:** open
+- **Author:** @fossabot
+- **Created:** 2018-05-12T22:37:04Z
+- **Branch:** master → master
+- **Diff:** [10.diff](./10.diff)
+
+---
+
+Your FOSSA integration was successful! Attached in this PR is a badge and license report to track scan status in your README.
+
+Below are docs for integrating FOSSA license checks into your CI:
+
+- [CircleCI](https://docs.fossa.io/docs/circleci)
+- [TravisCI](https://docs.fossa.io/docs/travisci)
+- [Jenkins](https://github.com/fossas/fossa-jenkins-plugin)
+- [Other](https://github.com/fossas/fossa-cli)
+
diff --git a/pulls/2.diff b/pulls/2.diff
@@ -0,0 +1,156 @@
+diff --git a/.circleci/config.yml b/.circleci/config.yml
+index 5f9a38f..4fee27f 100644
+--- a/.circleci/config.yml
++++ b/.circleci/config.yml
+@@ -41,7 +41,7 @@ jobs:
+ - run:
+ name: Run Build
+ working_directory: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/
+- command: /home/user/work/bin/qtdeploy build desktop
++ command: $GOPATH/bin/qtdeploy build linux
+ - run:
+ name: Prepare Deb Generating
+ working_directory: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/
+@@ -86,7 +86,7 @@ jobs:
+ - run:
+ name: Run Build
+ working_directory: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/
+- command: /home/user/work/bin/qtdeploy build windows
++ command: $GOPATH/bin/qtdeploy build windows
+ - store_artifacts:
+ path: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/deploy/windows/Morpheusv2.exe
+ destination: Morpheusv2.exe
+diff --git a/Gopkg.lock b/Gopkg.lock
+index ec45e23..13077c2 100644
+--- a/Gopkg.lock
++++ b/Gopkg.lock
+@@ -25,9 +25,15 @@
+ revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
+ version = "v1.0.1"
+
++[[projects]]
++ branch = "master"
++ name = "github.com/therecipe/qt"
++ packages = [".","core","gui","widgets"]
++ revision = "7038382d6c7bb5fd3957df56bbedf8ec4ca6b67c"
++
+ [solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+- inputs-digest = "9eae52af7d8c49e9a27a1863ba05582acb167fd5a5ce5bf23b6eb9288a20d0c2"
++ inputs-digest = "a82e2ac4eccca051143202632fee6ebf07b015e82f3d04c4bc426be93aab708b"
+ solver-name = "gps-cdcl"
+ solver-version = 1
+diff --git a/Gopkg.toml b/Gopkg.toml
+index b1ccb25..a975b22 100644
+--- a/Gopkg.toml
++++ b/Gopkg.toml
+@@ -21,8 +21,10 @@
+ # version = "2.4.0"
+
+
+-ignored = ["github.com/therecipe/qt/*"]
++[[constraint]]
++ branch = "master"
++ name = "github.com/shibukawa/configdir"
+
+ [[constraint]]
+ branch = "master"
+- name = "github.com/shibukawa/configdir"
+\ No newline at end of file
++ name = "github.com/therecipe/qt"
+diff --git a/cmd/root.go b/cmd/root.go
+index 61a0ac4..3374e09 100644
+--- a/cmd/root.go
++++ b/cmd/root.go
+@@ -22,6 +22,8 @@ import (
+ "github.com/spf13/cobra"
+ )
+
++var cfgFile string
++
+ // rootCmd represents the base command when called without any subcommands
+ var rootCmd = &cobra.Command{
+ Use: "Morpheusv2",
+@@ -46,4 +48,5 @@ func Execute() {
+ fmt.Println(err)
+ os.Exit(1)
+ }
++ os.Exit(0)
+ }
+diff --git a/deb.json b/deb.json
+index f710e5e..767176a 100644
+--- a/deb.json
++++ b/deb.json
+@@ -1,7 +1,7 @@
+ {
+ "name": "Morpheusv2",
+ "maintainer": "MTRNord <info@nordgedanken.de>",
+- "version": "0.1.0",
++ "version": "0.0.1",
+ "arch": "amd64",
+ "files": [
+ {
+@@ -50,7 +50,7 @@
+ "description":"A Matrix client written in Go-QT ",
+ "generic-name":"Matrix Client",
+ "exec":"/usr/bin/Morpheusv2.sh",
+- "icon":"pkg/qml/resources/logos/MorpheusBig.png",
++ "icon":"qml/resources/logos/MorpheusBig.png",
+ "type":"Application",
+ "keywords":"matrix;Morpheusv2",
+ "startup-notify": false,
+diff --git a/linter.json b/linter.json
+deleted file mode 100644
+index 2b2b1f4..0000000
+--- a/linter.json
++++ /dev/null
+@@ -1,22 +0,0 @@
+-{
+- "Vendor": true,
+- "Cyclo": 12,
+- "Deadline": "5m",
+- "Enable": [
+- "vetshadow",
+- "deadcode",
+- "gocyclo",
+- "golint",
+- "varcheck",
+- "structcheck",
+- "ineffassign",
+- "gas",
+- "misspell",
+- "unparam",
+- "errcheck",
+- "vet",
+- "megacheck",
+- "goconst",
+- "maligned"
+- ]
+-}
+\ No newline at end of file
+diff --git a/pkg/app/main.go b/pkg/app/main.go
+index 43d28a6..5caabde 100644
+--- a/pkg/app/main.go
++++ b/pkg/app/main.go
+@@ -24,7 +24,6 @@ import (
+ "path/filepath"
+ )
+
+-// Start prepares the Main QT Window and opens it
+ func Start(args []string) error {
+ log.Println("Starting Morpheus v2")
+
+diff --git a/pkg/mainThreadHelper.go b/pkg/mainThreadHelper.go
+index 4311a21..32b4d1a 100644
+--- a/pkg/mainThreadHelper.go
++++ b/pkg/mainThreadHelper.go
+@@ -27,7 +27,7 @@ func Main() {
+ // queue of work to run in main thread.
+ var mainfunc = make(chan func())
+
+-// Do runs f on the main thread.
++// do runs f on the main thread.
+ func Do(f func()) {
+ done := make(chan bool, 1)
+ mainfunc <- func() {
diff --git a/pulls/2.json b/pulls/2.json
@@ -0,0 +1,18 @@
+{
+ "number": 2,
+ "title": "Revert \"Fix CI building\"",
+ "state": "merged",
+ "diff_file": "2.diff",
+ "author": "MTRNord",
+ "created_at": "2018-05-01T16:34:30Z",
+ "closed_at": "2018-05-01T16:34:55Z",
+ "merged_at": "2018-05-01T16:34:55Z",
+ "base_ref": "master",
+ "head_ref": "revert-1-develop",
+ "labels": [],
+ "assignees": [],
+ "requested_reviewers": [],
+ "body": "Reverts Nordgedanken/Morpheusv2#1",
+ "comments": [],
+ "review_comments": []
+}
diff --git a/pulls/2.md b/pulls/2.md
@@ -0,0 +1,13 @@
+# PR #2 Revert "Fix CI building"
+
+- **Status:** merged
+- **Author:** @MTRNord
+- **Created:** 2018-05-01T16:34:30Z
+- **Branch:** revert-1-develop → master
+- **Merged:** 2018-05-01T16:34:55Z
+- **Diff:** [2.diff](./2.diff)
+
+---
+
+Reverts Nordgedanken/Morpheusv2#1
+
diff --git a/pulls/3.diff b/pulls/3.diff
@@ -0,0 +1,156 @@
+diff --git a/.circleci/config.yml b/.circleci/config.yml
+index 4fee27f..5f9a38f 100644
+--- a/.circleci/config.yml
++++ b/.circleci/config.yml
+@@ -41,7 +41,7 @@ jobs:
+ - run:
+ name: Run Build
+ working_directory: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/
+- command: $GOPATH/bin/qtdeploy build linux
++ command: /home/user/work/bin/qtdeploy build desktop
+ - run:
+ name: Prepare Deb Generating
+ working_directory: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/
+@@ -86,7 +86,7 @@ jobs:
+ - run:
+ name: Run Build
+ working_directory: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/
+- command: $GOPATH/bin/qtdeploy build windows
++ command: /home/user/work/bin/qtdeploy build windows
+ - store_artifacts:
+ path: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/deploy/windows/Morpheusv2.exe
+ destination: Morpheusv2.exe
+diff --git a/Gopkg.lock b/Gopkg.lock
+index 13077c2..ec45e23 100644
+--- a/Gopkg.lock
++++ b/Gopkg.lock
+@@ -25,15 +25,9 @@
+ revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
+ version = "v1.0.1"
+
+-[[projects]]
+- branch = "master"
+- name = "github.com/therecipe/qt"
+- packages = [".","core","gui","widgets"]
+- revision = "7038382d6c7bb5fd3957df56bbedf8ec4ca6b67c"
+-
+ [solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+- inputs-digest = "a82e2ac4eccca051143202632fee6ebf07b015e82f3d04c4bc426be93aab708b"
++ inputs-digest = "9eae52af7d8c49e9a27a1863ba05582acb167fd5a5ce5bf23b6eb9288a20d0c2"
+ solver-name = "gps-cdcl"
+ solver-version = 1
+diff --git a/Gopkg.toml b/Gopkg.toml
+index a975b22..b1ccb25 100644
+--- a/Gopkg.toml
++++ b/Gopkg.toml
+@@ -21,10 +21,8 @@
+ # version = "2.4.0"
+
+
+-[[constraint]]
+- branch = "master"
+- name = "github.com/shibukawa/configdir"
++ignored = ["github.com/therecipe/qt/*"]
+
+ [[constraint]]
+ branch = "master"
+- name = "github.com/therecipe/qt"
++ name = "github.com/shibukawa/configdir"
+\ No newline at end of file
+diff --git a/cmd/root.go b/cmd/root.go
+index 3374e09..61a0ac4 100644
+--- a/cmd/root.go
++++ b/cmd/root.go
+@@ -22,8 +22,6 @@ import (
+ "github.com/spf13/cobra"
+ )
+
+-var cfgFile string
+-
+ // rootCmd represents the base command when called without any subcommands
+ var rootCmd = &cobra.Command{
+ Use: "Morpheusv2",
+@@ -48,5 +46,4 @@ func Execute() {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+- os.Exit(0)
+ }
+diff --git a/deb.json b/deb.json
+index 767176a..f710e5e 100644
+--- a/deb.json
++++ b/deb.json
+@@ -1,7 +1,7 @@
+ {
+ "name": "Morpheusv2",
+ "maintainer": "MTRNord <info@nordgedanken.de>",
+- "version": "0.0.1",
++ "version": "0.1.0",
+ "arch": "amd64",
+ "files": [
+ {
+@@ -50,7 +50,7 @@
+ "description":"A Matrix client written in Go-QT ",
+ "generic-name":"Matrix Client",
+ "exec":"/usr/bin/Morpheusv2.sh",
+- "icon":"qml/resources/logos/MorpheusBig.png",
++ "icon":"pkg/qml/resources/logos/MorpheusBig.png",
+ "type":"Application",
+ "keywords":"matrix;Morpheusv2",
+ "startup-notify": false,
+diff --git a/linter.json b/linter.json
+new file mode 100644
+index 0000000..2b2b1f4
+--- /dev/null
++++ b/linter.json
+@@ -0,0 +1,22 @@
++{
++ "Vendor": true,
++ "Cyclo": 12,
++ "Deadline": "5m",
++ "Enable": [
++ "vetshadow",
++ "deadcode",
++ "gocyclo",
++ "golint",
++ "varcheck",
++ "structcheck",
++ "ineffassign",
++ "gas",
++ "misspell",
++ "unparam",
++ "errcheck",
++ "vet",
++ "megacheck",
++ "goconst",
++ "maligned"
++ ]
++}
+\ No newline at end of file
+diff --git a/pkg/app/main.go b/pkg/app/main.go
+index 5caabde..43d28a6 100644
+--- a/pkg/app/main.go
++++ b/pkg/app/main.go
+@@ -24,6 +24,7 @@ import (
+ "path/filepath"
+ )
+
++// Start prepares the Main QT Window and opens it
+ func Start(args []string) error {
+ log.Println("Starting Morpheus v2")
+
+diff --git a/pkg/mainThreadHelper.go b/pkg/mainThreadHelper.go
+index 32b4d1a..4311a21 100644
+--- a/pkg/mainThreadHelper.go
++++ b/pkg/mainThreadHelper.go
+@@ -27,7 +27,7 @@ func Main() {
+ // queue of work to run in main thread.
+ var mainfunc = make(chan func())
+
+-// do runs f on the main thread.
++// Do runs f on the main thread.
+ func Do(f func()) {
+ done := make(chan bool, 1)
+ mainfunc <- func() {
diff --git a/pulls/3.json b/pulls/3.json
@@ -0,0 +1,18 @@
+{
+ "number": 3,
+ "title": "Fix CI",
+ "state": "merged",
+ "diff_file": "3.diff",
+ "author": "MTRNord",
+ "created_at": "2018-05-01T16:37:03Z",
+ "closed_at": "2018-05-01T16:37:18Z",
+ "merged_at": "2018-05-01T16:37:18Z",
+ "base_ref": "master",
+ "head_ref": "develop",
+ "labels": [],
+ "assignees": [],
+ "requested_reviewers": [],
+ "body": "",
+ "comments": [],
+ "review_comments": []
+}
diff --git a/pulls/3.md b/pulls/3.md
@@ -0,0 +1,13 @@
+# PR #3 Fix CI
+
+- **Status:** merged
+- **Author:** @MTRNord
+- **Created:** 2018-05-01T16:37:03Z
+- **Branch:** develop → master
+- **Merged:** 2018-05-01T16:37:18Z
+- **Diff:** [3.diff](./3.diff)
+
+---
+
+_No description._
+
diff --git a/pulls/4.diff b/pulls/4.diff
@@ -0,0 +1,464 @@
+diff --git a/.circleci/config.yml b/.circleci/config.yml
+index 5f9a38f..4f0571c 100644
+--- a/.circleci/config.yml
++++ b/.circleci/config.yml
+@@ -21,12 +21,18 @@ jobs:
+ name: Get Go Dependencies
+ working_directory: /home/user/work/src/github.com/Nordgedanken/Morpheusv2/
+ command: dep ensure
++ - run:
++ name: Setup Code Climate test-reporter
++ command: |
++ curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
++ chmod +x ./cc-test-reporter
+ - persist_to_workspace:
+ # Must be an absolute path, or relative path from working_directory
+ root: /home/user/work/
+ # Must be relative path from root
+ paths:
+ - src/
++ - ./cc-test-reporter
+ build_linux:
+ docker:
+ - image: therecipe/qt:linux
+diff --git a/Gopkg.lock b/Gopkg.lock
+index 6773bcc..7859130 100644
+--- a/Gopkg.lock
++++ b/Gopkg.lock
+@@ -7,6 +7,12 @@
+ revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
+ version = "v1.0"
+
++[[projects]]
++ branch = "master"
++ name = "github.com/matrix-org/gomatrix"
++ packages = ["."]
++ revision = "a7fc80c8060c2544fe5d4dae465b584f8e9b4e27"
++
+ [[projects]]
+ branch = "master"
+ name = "github.com/shibukawa/configdir"
+diff --git a/cmd/root.go b/cmd/root.go
+index 61a0ac4..148f65a 100644
+--- a/cmd/root.go
++++ b/cmd/root.go
+@@ -19,19 +19,57 @@ import (
+ "os"
+
+ "github.com/Nordgedanken/Morpheusv2/pkg/app"
++ dbImpl "github.com/Nordgedanken/Morpheusv2/pkg/db/implementation"
++ "github.com/shibukawa/configdir"
+ "github.com/spf13/cobra"
++ "io"
++ "log"
++ "path/filepath"
+ )
+
+ // rootCmd represents the base command when called without any subcommands
+ var rootCmd = &cobra.Command{
+- Use: "Morpheusv2",
+- Short: "A brief description of your application",
+- Long: `A longer description that spans multiple lines and likely contains
+-examples and usage of using your application. For example:
+-
+-Cobra is a CLI library for Go that empowers applications.
+-This application is a tool to generate the needed files
+-to quickly create a Cobra application.`,
++ Use: "Morpheusv2",
++ PreRunE: func(cmd *cobra.Command, args []string) error {
++ // Init Logs and folders
++ // configdir.New gets the Config Paths that are available on this system
++ configDirs := configdir.New("Nordgedanken", "Morpheusv2")
++ // path holds the global configdir of the system with the log folder appended
++ path := filepath.ToSlash(configDirs.QueryFolders(configdir.Global)[0].Path + "/log/")
++ logFilePath := filepath.ToSlash(path + "main.log")
++
++ // This checks if the directory is missing and if that's the case to generate the directory
++ if _, StatErr := os.Stat(path); os.IsNotExist(StatErr) {
++ MkdirErr := os.MkdirAll(path, os.ModeDir)
++ if MkdirErr != nil {
++ return MkdirErr
++ }
++ }
++
++ // os.OpenFile opens the file where the log is supposed to be written to
++ logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
++ if err != nil {
++ return err
++ }
++
++ // MultiWriter makes it possible to print log to both log File and console
++ mw := io.MultiWriter(os.Stdout, logFile)
++
++ // SetOutput tells the log where to write to
++ log.SetOutput(mw)
++
++ // dbImpl.Init() generates the needed tables if needed before the app starts
++ err = dbImpl.Init()
++ if err != nil {
++ return err
++ }
++
++ log.Println("DB Set Up")
++ return nil
++ },
++ // TODO add descriptions
++ Short: "",
++ Long: ``,
+ // Uncomment the following line if your bare application
+ // has an action associated with it:
+ RunE: func(cmd *cobra.Command, args []string) error {
+diff --git a/deb.json b/deb.json
+index f710e5e..3a72561 100644
+--- a/deb.json
++++ b/deb.json
+@@ -50,7 +50,7 @@
+ "description":"A Matrix client written in Go-QT ",
+ "generic-name":"Matrix Client",
+ "exec":"/usr/bin/Morpheusv2.sh",
+- "icon":"pkg/qml/resources/logos/MorpheusBig.png",
++ "icon":"qml/resources/logos/MorpheusBig.png",
+ "type":"Application",
+ "keywords":"matrix;Morpheusv2",
+ "startup-notify": false,
+diff --git a/main.go b/main.go
+index f305e76..06c10b1 100644
+--- a/main.go
++++ b/main.go
+@@ -16,24 +16,18 @@ package main
+
+ import (
+ "github.com/Nordgedanken/Morpheusv2/cmd"
+- "github.com/Nordgedanken/Morpheusv2/pkg"
+- "runtime"
++ "os"
++ "os/signal"
++ "syscall"
+ )
+
+-// Arrange that main.main runs on main thread.
+-func init() {
+- runtime.LockOSThread()
+-}
++var c = make(chan os.Signal, 2)
+
+ func main() {
+- go pkg.Do(cmd.Execute)
++ signal.Notify(c, os.Interrupt, syscall.SIGTERM)
+ go func() {
+- for {
+- pkg.Do(noop)
+- }
++ <-c
++ os.Exit(1)
+ }()
+-
+- pkg.Main()
++ cmd.Execute()
+ }
+-
+-func noop() {}
+diff --git a/pkg/app/main.go b/pkg/app/main.go
+index 43d28a6..3832900 100644
+--- a/pkg/app/main.go
++++ b/pkg/app/main.go
+@@ -15,28 +15,37 @@
+ package app
+
+ import (
+- "github.com/shibukawa/configdir"
++ "github.com/Nordgedanken/Morpheusv2/pkg/mainUI"
++ "github.com/matrix-org/gomatrix"
+ "github.com/therecipe/qt/core"
+ "github.com/therecipe/qt/gui"
+ "github.com/therecipe/qt/widgets"
+ "log"
+- "os"
+- "path/filepath"
+ )
+
++var args []string
++var cli *gomatrix.Client
++var windowHeight = 600
++var windowWidth = 950
++var window *widgets.QMainWindow
++
+ // Start prepares the Main QT Window and opens it
+-func Start(args []string) error {
++func Start(argsArg []string) error {
++ args = argsArg
+ log.Println("Starting Morpheus v2")
+
+- // Init Logs and folders
+- configDirs := configdir.New("Nordgedanken", "Morpheus")
+- if _, StatErr := os.Stat(filepath.ToSlash(configDirs.QueryFolders(configdir.Global)[0].Path) + "/log/"); os.IsNotExist(StatErr) {
+- MkdirErr := os.MkdirAll(filepath.ToSlash(configDirs.QueryFolders(configdir.Global)[0].Path)+"/log/", 0700)
+- if MkdirErr != nil {
+- return MkdirErr
+- }
+- }
++ initApp()
++
++ mainUIS := mainUI.NewMainUI(windowWidth, windowHeight, window)
++ SetNewWindow(mainUIS, window)
++
++ widgets.QApplication_Exec()
+
++ return nil
++}
++
++func initApp() {
++ log.Println("Create QApp")
+ app := widgets.NewQApplication(len(args), args)
+
+ app.SetAttribute(core.Qt__AA_UseHighDpiPixmaps, true)
+@@ -44,22 +53,33 @@ func Start(args []string) error {
+ app.SetApplicationVersion("0.1.0")
+ appIcon := gui.NewQIcon5(":/qml/resources/logos/MorpheusBig.png")
+ app.SetWindowIcon(appIcon)
++ window = widgets.NewQMainWindow(nil, 0)
++ app.SetActiveWindow(window)
+
+- window := widgets.NewQMainWindow(nil, 0)
+-
+- windowHeight := 600
+- windowWidth := 950
+-
+- desktopApp := widgets.QApplication_Desktop()
++ desktopApp := app.Desktop()
+ primaryScreen := desktopApp.PrimaryScreen()
+ screen := desktopApp.Screen(primaryScreen)
+ windowX := (screen.Width() - windowHeight) / 2
+ windowY := (screen.Height() - windowWidth) / 2
+
+ window.Resize2(windowWidth, windowHeight)
+- window.Show()
+-
+ window.Move2(windowX, windowY)
+
++ app.ConnectQuit(func() {
++ log.Println("Morpheus closed")
++ })
++
++}
++
++// SetNewWindow loads the new UI into the QMainWindow
++func SetNewWindow(ui ui, window *widgets.QMainWindow) error {
++ ui.SetCli(cli)
++ uiErr := ui.NewUI()
++ if uiErr != nil {
++ return uiErr
++ }
++ ui.GetWidget().Resize2(windowWidth, windowHeight)
++ window.SetCentralWidget(ui.GetWidget())
++ window.Show()
+ return nil
+ }
+diff --git a/pkg/app/ui.go b/pkg/app/ui.go
+new file mode 100644
+index 0000000..37ced17
+--- /dev/null
++++ b/pkg/app/ui.go
+@@ -0,0 +1,12 @@
++package app
++
++import (
++ "github.com/matrix-org/gomatrix"
++ "github.com/therecipe/qt/widgets"
++)
++
++type ui interface {
++ SetCli(cli *gomatrix.Client)
++ GetWidget() (widget *widgets.QWidget)
++ NewUI() error
++}
+diff --git a/pkg/db/db.go b/pkg/db/db.go
+new file mode 100644
+index 0000000..0ffaede
+--- /dev/null
++++ b/pkg/db/db.go
+@@ -0,0 +1,14 @@
++package db
++
++import "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++
++// DB defines a Interface to allow multiple DB Implementations
++type DB interface {
++ SaveRoom(Room matrix.Room) error
++ GetRooms() (rooms map[string]matrix.Room, err error)
++ GetRoom(roomID string) (room matrix.Room, err error)
++
++ SaveUser(user matrix.User) error
++ GetUsers() (map[string]matrix.User, error)
++ GetCurrentUser() (matrix.User, error)
++}
+diff --git a/pkg/db/implementation/db.go b/pkg/db/implementation/db.go
+new file mode 100644
+index 0000000..9429d4b
+--- /dev/null
++++ b/pkg/db/implementation/db.go
+@@ -0,0 +1,51 @@
++package implementation
++
++import (
++ "database/sql"
++ "fmt"
++ _ "github.com/mattn/go-sqlite3" // Go-sqlite3 side effect import needed to use SQLite3 databases
++ "github.com/shibukawa/configdir"
++ "log"
++ "path/filepath"
++)
++
++var db *sql.DB
++
++// Init prepares the DB by opening it and creating the required tables if needed
++// TODO: Make part of the interface
++func Init() (err error) {
++ log.Println("Start setting up DB")
++ var openErr error
++
++ // Open the data.db file. It will be created if it doesn't exist.
++ configDirs := configdir.New("Nordgedanken", "Morpheusv2")
++ filePath := filepath.ToSlash(configDirs.QueryFolders(configdir.Global)[0].Path)
++
++ log.Println("DBFilePath: ", filePath+"/data.db")
++ db, openErr = sql.Open("sqlite3", filePath+"/data.db")
++ if openErr != nil {
++ err = openErr
++ return
++ }
++
++ log.Println("Creating DB Tables if needed")
++ createTables := `CREATE TABLE IF NOT EXISTS users (id integer not null primary key, display_name text, avatar text);
++ CREATE TABLE IF NOT EXISTS messages (id integer not null primary key, author text, message text, timestamp text, pure_event text);
++ CREATE TABLE IF NOT EXISTS rooms (id integer not null primary key, room_aliases text, room_id text, room_name text, room_avatar text, room_topic text, room_messages text);
++ `
++ _, execErr := db.Exec(createTables)
++ if execErr != nil {
++ err = fmt.Errorf("DB EXEC ERR: %s", execErr)
++ return
++ }
++ log.Println("Finished setting DB Setup")
++ return
++}
++
++// Open returns the in Init() created db variable
++func Open() *sql.DB {
++ if db != nil {
++ return db
++ }
++ return nil
++}
+diff --git a/pkg/mainUI/mainUI.go b/pkg/mainUI/mainUI.go
+new file mode 100644
+index 0000000..7fcaaf9
+--- /dev/null
++++ b/pkg/mainUI/mainUI.go
+@@ -0,0 +1,63 @@
++package mainUI
++
++import (
++ "github.com/matrix-org/gomatrix"
++ "github.com/therecipe/qt/core"
++ "github.com/therecipe/qt/gui"
++ "github.com/therecipe/qt/uitools"
++ "github.com/therecipe/qt/widgets"
++)
++
++// MainUI defines the data for the main ui (that one with the chats)
++type MainUI struct {
++ widget *widgets.QWidget
++ cli *gomatrix.Client
++ window *widgets.QMainWindow
++ windowWidth int
++ windowHeight int
++}
++
++// NewMainUI gives you a MainUI struct with prefilled data
++func NewMainUI(windowWidth, windowHeight int, window *widgets.QMainWindow) (mainUI *MainUI) {
++ mainUI = &MainUI{
++ windowWidth: windowWidth,
++ windowHeight: windowHeight,
++ window: window,
++ }
++ return
++}
++
++// SetCli sets the gomatrix Client for the MainUI
++func (m *MainUI) SetCli(cli *gomatrix.Client) {
++ m.cli = cli
++}
++
++// GetWidget returns the QWidget of the MainUI
++func (m *MainUI) GetWidget() (widget *widgets.QWidget) {
++ return m.widget
++}
++
++// NewUI prepares the new UI
++func (m *MainUI) NewUI() error {
++ m.widget = widgets.NewQWidget(nil, 0)
++
++ var loader = uitools.NewQUiLoader(nil)
++ var file = core.NewQFile2(":/qml/ui/chat.ui")
++
++ file.Open(core.QIODevice__ReadOnly)
++ mainWidget := loader.Load(file, m.widget)
++ file.Close()
++
++ var layout = widgets.NewQHBoxLayout()
++ m.window.SetLayout(layout)
++ layout.InsertWidget(0, mainWidget, 0, core.Qt__AlignTop|core.Qt__AlignLeft)
++ layout.SetSpacing(0)
++ layout.SetContentsMargins(0, 0, 0, 0)
++
++ m.widget.ConnectResizeEvent(func(event *gui.QResizeEvent) {
++ mainWidget.Resize(event.Size())
++ event.Accept()
++ })
++
++ return nil
++}
+diff --git a/pkg/matrix/dataTypes.go b/pkg/matrix/dataTypes.go
+new file mode 100644
+index 0000000..8d30e68
+--- /dev/null
++++ b/pkg/matrix/dataTypes.go
+@@ -0,0 +1,38 @@
++package matrix
++
++import (
++ "github.com/matrix-org/gomatrix"
++ "time"
++)
++
++// User defines a Interface to allow multiple User type Implementations
++type User interface {
++ SetCli(cli *gomatrix.Client)
++ SetMXID(id string)
++ GetDisplayName(roomID string) (string, error)
++ GetAvatar(roomID string) (string, error)
++}
++
++// Room defines a Interface to allow multiple Room type Implementations
++type Room interface {
++ // Handled using global "own User"
++ //SetCli(cli *gomatrix.Client)
++ SetRoomID(id string)
++ SetRoomAliases(aliases map[int64]string)
++ GetName() (string, error)
++ GetAvatar() (string, error)
++ GetTopic() (string, error)
++ GetMessages() (map[string]Message, error)
++}
++
++// Message defines a Interface to allow multiple Message type Implementations
++type Message interface {
++ // Handled using global "own User"
++ //SetCli(cli *gomatrix.Client)
++ SetEventID(id string)
++ SetEvent(event *gomatrix.Event)
++ SetAuthorMXID(mxid string)
++ SetMessage(message string)
++ SetTimestamp(ts *time.Time)
++ Show() error
++}
diff --git a/pulls/4.json b/pulls/4.json
@@ -0,0 +1,22 @@
+{
+ "number": 4,
+ "title": "Implement basic state managment for rooms, messages, users (not state as in matrix proto state)",
+ "state": "merged",
+ "diff_file": "4.diff",
+ "author": "MTRNord",
+ "created_at": "2018-05-02T16:43:24Z",
+ "closed_at": "2018-05-02T17:47:47Z",
+ "merged_at": "2018-05-02T17:47:47Z",
+ "base_ref": "master",
+ "head_ref": "develop",
+ "labels": [
+ "enhancement"
+ ],
+ "assignees": [
+ "MTRNord"
+ ],
+ "requested_reviewers": [],
+ "body": "",
+ "comments": [],
+ "review_comments": []
+}
diff --git a/pulls/4.md b/pulls/4.md
@@ -0,0 +1,15 @@
+# PR #4 Implement basic state managment for rooms, messages, users (not state as in matrix proto state)
+
+- **Status:** merged
+- **Author:** @MTRNord
+- **Created:** 2018-05-02T16:43:24Z
+- **Branch:** develop → master
+- **Merged:** 2018-05-02T17:47:47Z
+- **Labels:** enhancement
+- **Assignees:** @MTRNord
+- **Diff:** [4.diff](./4.diff)
+
+---
+
+_No description._
+
diff --git a/pulls/6.diff b/pulls/6.diff
@@ -0,0 +1,1269 @@
+diff --git a/Gopkg.lock b/Gopkg.lock
+index 7859130..629ec69 100644
+--- a/Gopkg.lock
++++ b/Gopkg.lock
+@@ -13,6 +13,12 @@
+ packages = ["."]
+ revision = "a7fc80c8060c2544fe5d4dae465b584f8e9b4e27"
+
++[[projects]]
++ name = "github.com/mattn/go-sqlite3"
++ packages = ["."]
++ revision = "6c771bb9887719704b210e87e934f08be014bdb1"
++ version = "v1.6.0"
++
+ [[projects]]
+ branch = "master"
+ name = "github.com/shibukawa/configdir"
+@@ -34,6 +40,6 @@
+ [solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+- inputs-digest = "c22db96d1e74b32e9427a6f762b2be5797dcc8426407dc4769795fe6ca7296be"
++ inputs-digest = "f746b36e895639f6b0cbe2cb4d928637d254f83f60346a95eaf5c0f383683229"
+ solver-name = "gps-cdcl"
+ solver-version = 1
+diff --git a/cmd/root.go b/cmd/root.go
+index 148f65a..9b10937 100644
+--- a/cmd/root.go
++++ b/cmd/root.go
+@@ -19,7 +19,8 @@ import (
+ "os"
+
+ "github.com/Nordgedanken/Morpheusv2/pkg/app"
+- dbImpl "github.com/Nordgedanken/Morpheusv2/pkg/db/implementation"
++ "github.com/Nordgedanken/Morpheusv2/pkg/db/sqlite"
++ "github.com/Nordgedanken/Morpheusv2/pkg/util"
+ "github.com/shibukawa/configdir"
+ "github.com/spf13/cobra"
+ "io"
+@@ -47,7 +48,7 @@ var rootCmd = &cobra.Command{
+ }
+
+ // os.OpenFile opens the file where the log is supposed to be written to
+- logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
++ logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0600)
+ if err != nil {
+ return err
+ }
+@@ -59,7 +60,8 @@ var rootCmd = &cobra.Command{
+ log.SetOutput(mw)
+
+ // dbImpl.Init() generates the needed tables if needed before the app starts
+- err = dbImpl.Init()
++ util.DB = &sqlite.SQLite{}
++ err = util.DB.Init()
+ if err != nil {
+ return err
+ }
+diff --git a/pkg/app/main.go b/pkg/app/main.go
+index 3832900..255f074 100644
+--- a/pkg/app/main.go
++++ b/pkg/app/main.go
+@@ -15,7 +15,10 @@
+ package app
+
+ import (
++ "database/sql"
++ "github.com/Nordgedanken/Morpheusv2/pkg/loginUI"
+ "github.com/Nordgedanken/Morpheusv2/pkg/mainUI"
++ "github.com/Nordgedanken/Morpheusv2/pkg/util"
+ "github.com/matrix-org/gomatrix"
+ "github.com/therecipe/qt/core"
+ "github.com/therecipe/qt/gui"
+@@ -36,11 +39,20 @@ func Start(argsArg []string) error {
+
+ initApp()
+
+- mainUIS := mainUI.NewMainUI(windowWidth, windowHeight, window)
+- SetNewWindow(mainUIS, window)
++ _, err := util.DB.GetCurrentUser()
++ // We special case ErrNoRows because this is expected to happen if user is missing
++ if err == sql.ErrNoRows {
++ loginUIs := loginUI.NewLoginUI(windowWidth, windowHeight, window)
++ SetNewWindow(loginUIs, window)
++ } else if err != nil {
++ return err
++ } else {
++ mainUIs := mainUI.NewMainUI(windowWidth, windowHeight, window)
++ SetNewWindow(mainUIs, window)
++ }
+
+ widgets.QApplication_Exec()
+-
++
+ return nil
+ }
+
+@@ -65,7 +77,7 @@ func initApp() {
+ window.Resize2(windowWidth, windowHeight)
+ window.Move2(windowX, windowY)
+
+- app.ConnectQuit(func() {
++ window.ConnectCloseEvent(func(event *gui.QCloseEvent) {
+ log.Println("Morpheus closed")
+ })
+
+diff --git a/pkg/app/ui.go b/pkg/app/ui.go
+index 37ced17..7273079 100644
+--- a/pkg/app/ui.go
++++ b/pkg/app/ui.go
+@@ -1,3 +1,17 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
+ package app
+
+ import (
+diff --git a/pkg/db/db.go b/pkg/db/db.go
+index 0ffaede..27f04b8 100644
+--- a/pkg/db/db.go
++++ b/pkg/db/db.go
+@@ -1,14 +1,37 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
+ package db
+
+-import "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++import (
++ "database/sql"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++)
+
+ // DB defines a Interface to allow multiple DB Implementations
+ type DB interface {
++ Init() error
++ Open() *sql.DB
++
+ SaveRoom(Room matrix.Room) error
+- GetRooms() (rooms map[string]matrix.Room, err error)
+- GetRoom(roomID string) (room matrix.Room, err error)
++ GetRooms() (roomsR []matrix.Room, err error)
++ GetRoom(roomID string) (roomR matrix.Room, err error)
+
+ SaveUser(user matrix.User) error
+- GetUsers() (map[string]matrix.User, error)
+- GetCurrentUser() (matrix.User, error)
++ GetUser(userID string) (userR matrix.User, err error)
++ GetCurrentUser() (userR matrix.User, err error)
++
++ SaveMessage(message matrix.Message) error
++ GetMessage(eventID string) (messageR matrix.Message, err error)
+ }
+diff --git a/pkg/db/sqlite/db.go b/pkg/db/sqlite/db.go
+new file mode 100644
+index 0000000..fa80421
+--- /dev/null
++++ b/pkg/db/sqlite/db.go
+@@ -0,0 +1,62 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package sqlite
++
++import (
++ "database/sql"
++ "fmt"
++ _ "github.com/mattn/go-sqlite3" // Go-sqlite3 side effect import needed to use SQLite3 databases
++ "github.com/shibukawa/configdir"
++ "log"
++ "path/filepath"
++)
++
++// Init prepares the DB by opening it and creating the required tables if needed
++func (s *SQLite) Init() (err error) {
++ log.Println("Start setting up DB")
++ var openErr error
++
++ // Open the data.db file. It will be created if it doesn't exist.
++ configDirs := configdir.New("Nordgedanken", "Morpheusv2")
++ filePath := filepath.ToSlash(configDirs.QueryFolders(configdir.Global)[0].Path)
++
++ log.Println("DBFilePath: ", filePath+"/data.db")
++ s.db, openErr = sql.Open("sqlite3", filePath+"/data.db")
++ if openErr != nil {
++ err = openErr
++ return
++ }
++
++ log.Println("Creating DB Tables if needed")
++ createTables := `CREATE TABLE IF NOT EXISTS users (id varchar not null primary key, display_name text, avatar text, access_token text, own integer);
++ CREATE TABLE IF NOT EXISTS messages (id varchar not null primary key, author_id varchar, message text, timestamp datetime, pure_event text);
++ CREATE TABLE IF NOT EXISTS rooms (id varchar not null primary key, room_aliases text, room_name text, room_avatar text, room_topic text, room_messages text);
++ `
++ _, execErr := s.db.Exec(createTables)
++ if execErr != nil {
++ err = fmt.Errorf("DB EXEC ERR: %s", execErr)
++ return
++ }
++ log.Println("Finished setting DB Setup")
++ return
++}
++
++// Open returns the in Init() created db variable
++func (s *SQLite) Open() *sql.DB {
++ if s.db != nil {
++ return s.db
++ }
++ return nil
++}
+diff --git a/pkg/db/sqlite/messages.go b/pkg/db/sqlite/messages.go
+new file mode 100644
+index 0000000..6b709d7
+--- /dev/null
++++ b/pkg/db/sqlite/messages.go
+@@ -0,0 +1,93 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package sqlite
++
++import (
++ "encoding/json"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix/messages"
++ "github.com/matrix-org/gomatrix"
++ "time"
++)
++
++// SaveMessage saves message Events to the DB
++func (s *SQLite) SaveMessage(message matrix.Message) error {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ tx, err := s.db.Begin()
++ if err != nil {
++ return err
++ }
++
++ stmt, err := tx.Prepare("INSERT INTO messages (id, author_id, message, timestamp, pure_event) VALUES (?, ?, ?, ?, ?)")
++ if err != nil {
++ return err
++ }
++ defer stmt.Close()
++
++ id := message.GetEventID()
++ authorID := message.GetAuthorMXID()
++ messageS := message.GetMessage()
++ timestampR := message.GetTimestamp()
++ timestamp := timestampR.Format("2006-01-02 15:04:05")
++ pureEvent := message.GetEvent()
++ _, err = stmt.Exec(id, authorID, messageS, timestamp, pureEvent)
++ if err != nil {
++ return err
++ }
++
++ return tx.Commit()
++}
++
++// GetMessage returns the Message where the id matches the eventID
++func (s *SQLite) GetMessage(eventID string) (messageR matrix.Message, err error) {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ stmt, err := s.db.Prepare(`SELECT author_id, message, timestamp, pure_event FROM messages WHERE id=$1`)
++ if err != nil {
++ return
++ }
++ defer stmt.Close()
++
++ row := stmt.QueryRow(eventID)
++
++ var authorID string
++ var messageS string
++ var timestamp time.Time
++ var pureEvent string
++ err = row.Scan(&authorID, &messageS, ×tamp, &pureEvent)
++ if err != nil {
++ return
++ }
++
++ messageI := &messages.Message{}
++ messageI.SetEventID(eventID)
++ messageI.SetAuthorMXID(authorID)
++ messageI.SetMessage(messageS)
++ messageI.SetTimestamp(×tamp)
++ var gomatrixEvent gomatrix.Event
++ err = json.Unmarshal([]byte(pureEvent), &gomatrixEvent)
++ if err != nil {
++ return
++ }
++ messageI.SetEvent(&gomatrixEvent)
++
++ messageR = messageI
++ return
++}
+diff --git a/pkg/db/sqlite/rooms.go b/pkg/db/sqlite/rooms.go
+new file mode 100644
+index 0000000..1bfd627
+--- /dev/null
++++ b/pkg/db/sqlite/rooms.go
+@@ -0,0 +1,172 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package sqlite
++
++import (
++ "encoding/json"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix/rooms"
++)
++
++// SaveRoom saves a Room into the sqlite DB
++func (s *SQLite) SaveRoom(Room matrix.Room) error {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ tx, err := s.db.Begin()
++ if err != nil {
++ return err
++ }
++
++ stmt, err := tx.Prepare("INSERT INTO rooms (room_aliases, id, room_name, room_avatar, room_topic, room_messages) VALUES (?, ?, ?, ?, ?, ?)")
++ if err != nil {
++ return err
++ }
++ defer stmt.Close()
++
++ aliases := Room.GetRoomAliases()
++ aliasesBytes, err := json.Marshal(aliases)
++ if err != nil {
++ return err
++ }
++ aliasesS := string(aliasesBytes)
++ roomID := Room.GetRoomID()
++ name, err := Room.GetName()
++ if err != nil {
++ return err
++ }
++ avatar, err := Room.GetAvatar()
++ if err != nil {
++ return err
++ }
++ topic, err := Room.GetTopic()
++ if err != nil {
++ return err
++ }
++
++ messages := Room.GetMessages()
++ if err != nil {
++ return err
++ }
++ var messageIDs []string
++ for _, v := range messages {
++ messageIDs = append(messageIDs, v.GetEventID())
++ }
++
++ _, err = stmt.Exec(aliasesS, roomID, name, string(avatar), topic, messageIDs)
++ if err != nil {
++ return err
++ }
++ return tx.Commit()
++}
++
++// GetRooms returns all Rooms from the Database
++func (s *SQLite) GetRooms() (roomsR []matrix.Room, err error) {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ rows, err := s.db.Query("SELECT id, room_aliases, room_name, room_avatar, room_topic, room_messages FROM rooms")
++ if err != nil {
++ return
++ }
++ defer rows.Close()
++
++ for rows.Next() {
++ var roomID string
++ var roomAliases string
++ var roomName string
++ var roomAvatar string
++ var roomTopic string
++ var roomMessages string
++ err = rows.Scan(&roomID, &roomAliases, &roomName, &roomAvatar, &roomTopic, &roomMessages)
++ if err != nil {
++ return
++ }
++
++ roomI := &rooms.Room{}
++ roomI.SetRoomID(roomID)
++ var aliases []string
++ err = json.Unmarshal([]byte(roomAliases), &aliases)
++ if err != nil {
++ return
++ }
++ roomI.SetRoomAliases(aliases)
++ roomI.SetName(roomName)
++ roomI.SetAvatar([]byte(roomAvatar))
++ roomI.SetTopic(roomTopic)
++ var messageIDs []string
++ err = json.Unmarshal([]byte(roomMessages), &messageIDs)
++ if err != nil {
++ return
++ }
++ // TODO Convert IDs to messages slice using another call or from the beginning on using a JOIN
++ //roomI.SetMessages(messages)
++
++ roomsR = append(roomsR, roomI)
++ }
++
++ // get any error encountered during iteration
++ err = rows.Err()
++ return
++}
++
++// GetRoom returns the Room where the id matches the roomID
++func (s *SQLite) GetRoom(roomID string) (roomR matrix.Room, err error) {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ stmt, err := s.db.Prepare(`SELECT room_aliases, room_name, room_avatar, room_topic, room_messages FROM rooms WHERE id=$1`)
++ if err != nil {
++ return
++ }
++ defer stmt.Close()
++
++ row := stmt.QueryRow(roomID)
++
++ var roomAliases string
++ var roomName string
++ var roomAvatar string
++ var roomTopic string
++ var roomMessages string
++ err = row.Scan(&roomAliases, &roomName, &roomAvatar, &roomTopic, &roomMessages)
++ if err != nil {
++ return
++ }
++
++ roomI := &rooms.Room{}
++ roomI.SetRoomID(roomID)
++ var aliases []string
++ err = json.Unmarshal([]byte(roomAliases), &aliases)
++ if err != nil {
++ return
++ }
++ roomI.SetRoomAliases(aliases)
++ roomI.SetName(roomName)
++ roomI.SetAvatar([]byte(roomAvatar))
++ roomI.SetTopic(roomTopic)
++ var messageIDs []string
++ err = json.Unmarshal([]byte(roomMessages), &messageIDs)
++ if err != nil {
++ return
++ }
++ // TODO Convert IDs to messages slice using another call or from the beginning on using a JOIN
++ //roomI.SetMessages(messages)
++
++ roomR = roomI
++ return
++}
+diff --git a/pkg/db/sqlite/struct.go b/pkg/db/sqlite/struct.go
+new file mode 100644
+index 0000000..6497773
+--- /dev/null
++++ b/pkg/db/sqlite/struct.go
+@@ -0,0 +1,22 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package sqlite
++
++import "database/sql"
++
++// SQLite implements a SQLite database for the db.DB interface
++type SQLite struct {
++ db *sql.DB
++}
+diff --git a/pkg/db/sqlite/users.go b/pkg/db/sqlite/users.go
+new file mode 100644
+index 0000000..e78a6a6
+--- /dev/null
++++ b/pkg/db/sqlite/users.go
+@@ -0,0 +1,125 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package sqlite
++
++import (
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix/users"
++ "github.com/matrix-org/gomatrix"
++ "strings"
++)
++
++// SaveUser saves a matrix User to the User table
++func (s *SQLite) SaveUser(user matrix.User) error {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ tx, err := s.db.Begin()
++ if err != nil {
++ return err
++ }
++
++ stmt, err := tx.Prepare("INSERT INTO users (id, display_name, avatar) VALUES (?, ?, ?)")
++ if err != nil {
++ return err
++ }
++ defer stmt.Close()
++ displayName, err := user.GetDisplayName("")
++ if err != nil {
++ return err
++ }
++ avatar, err := user.GetAvatar("")
++ if err != nil {
++ return err
++ }
++ mxid := user.GetMXID()
++ _, err = stmt.Exec(mxid, displayName, string(avatar))
++ if err != nil {
++ return err
++ }
++
++ return tx.Commit()
++}
++
++// GetCurrentUser returns the current user including a ready gomatrix client
++func (s *SQLite) GetCurrentUser() (userR matrix.User, err error) {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ stmt, err := s.db.Prepare(`SELECT id, display_name, avatar, access_token FROM users WHERE own=1`)
++ if err != nil {
++ return
++ }
++ defer stmt.Close()
++
++ row := stmt.QueryRow()
++
++ var mxid string
++ var displayName string
++ var avatar string
++ var accessToken string
++ err = row.Scan(&mxid, &displayName, &avatar, &accessToken)
++ if err != nil {
++ return
++ }
++
++ userI := &users.User{}
++ userI.SetMXID(mxid)
++ userI.SetDisplayName("", displayName)
++ userI.SetAvatar("", []byte(avatar))
++
++ splitUser := strings.Split(mxid, ":")
++ domain := strings.TrimPrefix(mxid, splitUser[0]+":")
++ client, err := gomatrix.NewClient(domain, mxid, accessToken)
++ if err != nil {
++ return
++ }
++ userI.SetCli(client)
++
++ userR = userI
++ return
++}
++
++// GetUser returns a user matching the mxid of the argument
++func (s *SQLite) GetUser(userID string) (userR matrix.User, err error) {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ stmt, err := s.db.Prepare(`SELECT display_name, avatar FROM users WHERE id=$1`)
++ if err != nil {
++ return
++ }
++ defer stmt.Close()
++
++ row := stmt.QueryRow(userID)
++
++ var displayName string
++ var avatar string
++ err = row.Scan(&displayName, &avatar)
++ if err != nil {
++ return
++ }
++
++ userI := &users.User{}
++ userI.SetMXID(userID)
++ userI.SetDisplayName("", displayName)
++ userI.SetAvatar("", []byte(avatar))
++
++ userR = userI
++ return
++}
+diff --git a/pkg/loginUI/loginUI.go b/pkg/loginUI/loginUI.go
+new file mode 100644
+index 0000000..fa3d993
+--- /dev/null
++++ b/pkg/loginUI/loginUI.go
+@@ -0,0 +1,77 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package loginUI
++
++import (
++ "github.com/matrix-org/gomatrix"
++ "github.com/therecipe/qt/core"
++ "github.com/therecipe/qt/gui"
++ "github.com/therecipe/qt/uitools"
++ "github.com/therecipe/qt/widgets"
++)
++
++// LoginUI defines the data for the login ui
++type LoginUI struct {
++ widget *widgets.QWidget
++ cli *gomatrix.Client
++ window *widgets.QMainWindow
++ windowWidth int
++ windowHeight int
++}
++
++// NewLoginUI gives you a MainUI struct with profiled data
++func NewLoginUI(windowWidth, windowHeight int, window *widgets.QMainWindow) (loginUI *LoginUI) {
++ loginUI = &LoginUI{
++ windowWidth: windowWidth,
++ windowHeight: windowHeight,
++ window: window,
++ }
++ return
++}
++
++// SetCli sets the gomatrix Client for the LoginUI
++func (m *LoginUI) SetCli(cli *gomatrix.Client) {
++ m.cli = cli
++}
++
++// GetWidget returns the QWidget of the LoginUI
++func (m *LoginUI) GetWidget() (widget *widgets.QWidget) {
++ return m.widget
++}
++
++// NewUI prepares the new UI
++func (m *LoginUI) NewUI() error {
++ m.widget = widgets.NewQWidget(nil, 0)
++
++ var loader = uitools.NewQUiLoader(nil)
++ var file = core.NewQFile2(":/qml/ui/login.ui")
++
++ file.Open(core.QIODevice__ReadOnly)
++ mainWidget := loader.Load(file, m.widget)
++ file.Close()
++
++ var layout = widgets.NewQHBoxLayout()
++ m.window.SetLayout(layout)
++ layout.InsertWidget(0, mainWidget, 0, core.Qt__AlignTop|core.Qt__AlignLeft)
++ layout.SetSpacing(0)
++ layout.SetContentsMargins(0, 0, 0, 0)
++
++ m.widget.ConnectResizeEvent(func(event *gui.QResizeEvent) {
++ mainWidget.Resize(event.Size())
++ event.Accept()
++ })
++
++ return nil
++}
+diff --git a/pkg/mainUI/mainUI.go b/pkg/mainUI/mainUI.go
+index 7fcaaf9..a8cddc3 100644
+--- a/pkg/mainUI/mainUI.go
++++ b/pkg/mainUI/mainUI.go
+@@ -1,3 +1,17 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
+ package mainUI
+
+ import (
+diff --git a/pkg/matrix/dataTypes.go b/pkg/matrix/dataTypes.go
+index 8d30e68..a010373 100644
+--- a/pkg/matrix/dataTypes.go
++++ b/pkg/matrix/dataTypes.go
+@@ -1,3 +1,17 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
+ package matrix
+
+ import (
+@@ -9,8 +23,15 @@ import (
+ type User interface {
+ SetCli(cli *gomatrix.Client)
+ SetMXID(id string)
++ SetDisplayName(roomID string, name string)
++ SetAvatar(roomID string, avatar []byte)
++
++ GetMXID() string
+ GetDisplayName(roomID string) (string, error)
+- GetAvatar(roomID string) (string, error)
++ GetAvatar(roomID string) ([]byte, error)
++ GetCli() (cli *gomatrix.Client)
++
++ //Implement MarshalJSON() (b []byte, e error) as in http://gregtrowbridge.com/golang-json-serialization-with-interfaces/ to support json
+ }
+
+ // Room defines a Interface to allow multiple Room type Implementations
+@@ -18,11 +39,20 @@ type Room interface {
+ // Handled using global "own User"
+ //SetCli(cli *gomatrix.Client)
+ SetRoomID(id string)
+- SetRoomAliases(aliases map[int64]string)
++ SetRoomAliases(aliases []string)
++ SetName(name string)
++ SetAvatar(avatar []byte)
++ SetTopic(topic string)
++ SetMessages(messages []Message)
++
++ GetRoomID() string
++ GetRoomAliases() []string
+ GetName() (string, error)
+- GetAvatar() (string, error)
++ GetAvatar() ([]byte, error)
+ GetTopic() (string, error)
+- GetMessages() (map[string]Message, error)
++ GetMessages() []Message
++
++ //Implement MarshalJSON() (b []byte, e error) as in http://gregtrowbridge.com/golang-json-serialization-with-interfaces/ to support json
+ }
+
+ // Message defines a Interface to allow multiple Message type Implementations
+@@ -34,5 +64,14 @@ type Message interface {
+ SetAuthorMXID(mxid string)
+ SetMessage(message string)
+ SetTimestamp(ts *time.Time)
++
++ GetEventID() (id string)
++ GetEvent() (event *gomatrix.Event)
++ GetAuthorMXID() (mxid string)
++ GetMessage() (message string)
++ GetTimestamp() (ts *time.Time)
++
+ Show() error
++
++ //Implement MarshalJSON() (b []byte, e error) as in http://gregtrowbridge.com/golang-json-serialization-with-interfaces/ to support json
+ }
+diff --git a/pkg/matrix/messages/message.go b/pkg/matrix/messages/message.go
+new file mode 100644
+index 0000000..186fdda
+--- /dev/null
++++ b/pkg/matrix/messages/message.go
+@@ -0,0 +1,85 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package messages
++
++import (
++ "github.com/matrix-org/gomatrix"
++ "time"
++)
++
++// Message holds the needed Message data and allows to work with that. It gets normally loaded from the cache
++type Message struct {
++ eventID string
++ event *gomatrix.Event
++ authorID string
++ text string
++ timestamp *time.Time
++}
++
++// SetEventID adds the eventID to the current Message
++func (m *Message) SetEventID(id string) {
++ m.eventID = id
++}
++
++// SetEvent adds the gomatrix Event to the current Message
++func (m *Message) SetEvent(event *gomatrix.Event) {
++ m.event = event
++}
++
++// SetAuthorMXID adds the author MXID to the current Message
++func (m *Message) SetAuthorMXID(mxid string) {
++ m.authorID = mxid
++}
++
++// SetMessage adds the message Text to the current Message
++func (m *Message) SetMessage(message string) {
++ m.text = message
++}
++
++// SetTimestamp adds the Timestamp to the current Message
++func (m *Message) SetTimestamp(ts *time.Time) {
++ m.timestamp = ts
++}
++
++// GetEventID returns the event ID from the current Message
++func (m *Message) GetEventID() (id string) {
++ return m.eventID
++}
++
++// GetEvent returns the gomatrix event from the current Message
++func (m *Message) GetEvent() (event *gomatrix.Event) {
++ return m.event
++}
++
++// GetAuthorMXID returns the authors mxid from the current Message
++func (m *Message) GetAuthorMXID() (mxid string) {
++ return m.authorID
++}
++
++// GetMessage returns the text from the current Message
++func (m *Message) GetMessage() (message string) {
++ return m.text
++}
++
++// GetTimestamp returns the timestamp from the current Message
++func (m *Message) GetTimestamp() (ts *time.Time) {
++ return m.timestamp
++}
++
++// Show adds the current Message to the UI
++// TODO implement it
++func (m *Message) Show() error {
++ return nil
++}
+diff --git a/pkg/matrix/rooms/room.go b/pkg/matrix/rooms/room.go
+new file mode 100644
+index 0000000..9d884ce
+--- /dev/null
++++ b/pkg/matrix/rooms/room.go
+@@ -0,0 +1,145 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package rooms
++
++import (
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++ "github.com/Nordgedanken/Morpheusv2/pkg/util"
++ "github.com/matrix-org/gomatrix"
++ "strings"
++)
++
++// Room holds the needed Room data and allows to work with that. It gets normally loaded from the cache
++type Room struct {
++ id string
++ aliases []string
++ name string
++ avatar []byte
++ topic string
++ messages []matrix.Message
++}
++
++// SetRoomID adds the roomID to the current Room
++func (r *Room) SetRoomID(id string) {
++ r.id = id
++}
++
++// SetRoomAliases adds the aliases to the current Room
++func (r *Room) SetRoomAliases(aliases []string) {
++ r.aliases = aliases
++}
++
++// SetName adds the name to the current Room
++func (r *Room) SetName(name string) {
++ r.name = name
++}
++
++// SetAvatar adds the avatar to the current Room
++func (r *Room) SetAvatar(avatar []byte) {
++ r.avatar = avatar
++}
++
++// SetTopic adds the topic to the current Room
++func (r *Room) SetTopic(topic string) {
++ r.topic = topic
++}
++
++// SetMessages adds the messages to the current Room
++func (r *Room) SetMessages(messages []matrix.Message) {
++ r.messages = messages
++}
++
++// GetRoomID returns the room ID from the current Room
++func (r *Room) GetRoomID() string {
++ return r.id
++}
++
++// GetRoomAliases returns the room aliases from the current Room
++func (r *Room) GetRoomAliases() []string {
++ return r.aliases
++}
++
++// GetName returns the name from the current Room
++func (r *Room) GetName() (string, error) {
++ if r.name == "" {
++ type RespRoomName struct {
++ Name string `json:"name"`
++ }
++ resp := &RespRoomName{}
++ err := util.User.GetCli().StateEvent(r.id, "m.room.name", "", resp)
++ if err != nil {
++ return "", err
++ }
++ r.name = resp.Name
++ }
++ return r.name, nil
++}
++
++// GetAvatar returns the avatar from the current Room
++func (r *Room) GetAvatar() ([]byte, error) {
++ if r.avatar == nil {
++ resp := &gomatrix.Event{}
++ err := util.User.GetCli().StateEvent(r.id, "m.room.avatar", "", resp)
++ if err != nil {
++ return nil, err
++ }
++ var avatar []byte
++ value, exists := resp.Content["url"]
++ if !exists {
++ return nil, nil
++ }
++ url, ok := value.(string)
++ if !ok {
++ return nil, nil
++ }
++ split := strings.Split(url, "/")
++ servername := strings.TrimPrefix(split[0], "mxc://")
++ mediaID := split[1]
++ mediaURL := util.User.GetCli().BuildBaseURL("_matrix/media/r0/download", servername, mediaID)
++ avatar, err = util.User.GetCli().MakeRequest("GET", mediaURL, nil, nil)
++ if err != nil {
++ return nil, err
++ }
++ r.avatar = avatar
++ }
++ return r.avatar, nil
++}
++
++// GetTopic returns the topic from the current Room
++func (r *Room) GetTopic() (string, error) {
++ if r.topic == "" {
++ resp := &gomatrix.Event{}
++ err := util.User.GetCli().StateEvent(r.id, "m.room.topic", "", resp)
++ if err != nil {
++ return "", err
++ }
++ value, exists := resp.Content["topic"]
++ if !exists {
++ return "", nil
++ }
++ topic, ok := value.(string)
++ if !ok {
++ return "", nil
++ }
++ r.topic = topic
++ }
++ return r.topic, nil
++}
++
++// GetMessages returns the messages from the current Room
++func (r *Room) GetMessages() []matrix.Message {
++ // TODO Lazy load from DB
++ return r.messages
++}
+diff --git a/pkg/matrix/users/user.go b/pkg/matrix/users/user.go
+new file mode 100644
+index 0000000..8cee5cf
+--- /dev/null
++++ b/pkg/matrix/users/user.go
+@@ -0,0 +1,127 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package users
++
++import (
++ "github.com/Nordgedanken/Morpheusv2/pkg/util"
++ "github.com/matrix-org/gomatrix"
++ "strings"
++)
++
++// User holds the needed User data and allows to work with that. It gets normally loaded from the cache
++type User struct {
++ cli *gomatrix.Client
++ mxid string
++ defaultDisplayName string
++ displayName map[string]string
++ defaultAvatar []byte
++ avatar map[string][]byte
++}
++
++// SetCli adds the gomatrix.Client to the current User. This only happens if the User is the current User aka the one that logged into the client.
++func (u *User) SetCli(cli *gomatrix.Client) {
++ u.cli = cli
++}
++
++// SetMXID adds the mxid to the current User
++func (u *User) SetMXID(id string) {
++ u.mxid = id
++}
++
++// SetDisplayName adds the displayName to the current User
++func (u *User) SetDisplayName(roomID string, name string) {
++ if roomID == "" {
++ u.defaultDisplayName = name
++ } else {
++ if u.displayName == nil {
++ u.displayName = make(map[string]string)
++ }
++ u.displayName[roomID] = name
++ }
++}
++
++// SetAvatar adds the avatar to the current User
++func (u *User) SetAvatar(roomID string, avatar []byte) {
++ if roomID == "" {
++ u.defaultAvatar = avatar
++ } else {
++ if u.avatar == nil {
++ u.avatar = make(map[string][]byte)
++ }
++ u.avatar[roomID] = avatar
++ }
++}
++
++// GetMXID returns the mxid from the current User
++func (u *User) GetMXID() string {
++ return u.mxid
++}
++
++// GetDisplayName returns the displayName from the current User
++func (u *User) GetDisplayName(roomID string) (string, error) {
++ if roomID == "" {
++ if u.defaultDisplayName == "" {
++ resp, err := util.User.GetCli().GetDisplayName(u.mxid)
++ if err != nil {
++ return "", err
++ }
++ u.defaultDisplayName = resp.DisplayName
++ }
++ return u.defaultDisplayName, nil
++ }
++ // TODO get Membership Event from Room instead returning default directly
++ if u.displayName[roomID] == "" {
++ return u.defaultDisplayName, nil
++ }
++ return u.displayName[roomID], nil
++}
++
++// GetAvatar returns the avatar from the current User
++func (u *User) GetAvatar(roomID string) ([]byte, error) {
++ if roomID == "" {
++ if u.defaultAvatar == nil {
++ urlPath := util.User.GetCli().BuildURL("profile", u.mxid, "avatar_url")
++ s := struct {
++ AvatarURL string `json:"avatar_url"`
++ }{}
++
++ _, err := util.User.GetCli().MakeRequest("GET", urlPath, nil, &s)
++ if err != nil {
++ return nil, err
++ }
++
++ split := strings.Split(s.AvatarURL, "/")
++ servername := strings.TrimPrefix(split[0], "mxc://")
++ mediaID := split[1]
++ mediaURL := util.User.GetCli().BuildBaseURL("_matrix/media/r0/download", servername, mediaID)
++ avatar, err := util.User.GetCli().MakeRequest("GET", mediaURL, nil, nil)
++ if err != nil {
++ return nil, err
++ }
++ u.defaultAvatar = avatar
++ }
++ return u.defaultAvatar, nil
++ }
++ // TODO get Membership Event from Room instead returning default directly
++ if u.avatar[roomID] == nil {
++ return u.defaultAvatar, nil
++ }
++ return u.avatar[roomID], nil
++}
++
++// GetCli returns the gomatrix.Client from the current User
++func (u *User) GetCli() *gomatrix.Client {
++ return u.cli
++}
+diff --git a/pkg/util/vars.go b/pkg/util/vars.go
+new file mode 100644
+index 0000000..7325755
+--- /dev/null
++++ b/pkg/util/vars.go
+@@ -0,0 +1,26 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package util
++
++import (
++ "github.com/Nordgedanken/Morpheusv2/pkg/db"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++)
++
++// DB holds the main pointer to the Database
++var DB db.DB
++
++// User holds the Current User
++var User matrix.User
diff --git a/pulls/6.json b/pulls/6.json
@@ -0,0 +1,22 @@
+{
+ "number": 6,
+ "title": "Finish backend work",
+ "state": "merged",
+ "diff_file": "6.diff",
+ "author": "MTRNord",
+ "created_at": "2018-05-05T23:01:20Z",
+ "closed_at": "2018-05-05T23:09:51Z",
+ "merged_at": "2018-05-05T23:09:51Z",
+ "base_ref": "master",
+ "head_ref": "develop",
+ "labels": [
+ "enhancement"
+ ],
+ "assignees": [
+ "MTRNord"
+ ],
+ "requested_reviewers": [],
+ "body": "Still todo is interface to json processing",
+ "comments": [],
+ "review_comments": []
+}
diff --git a/pulls/6.md b/pulls/6.md
@@ -0,0 +1,15 @@
+# PR #6 Finish backend work
+
+- **Status:** merged
+- **Author:** @MTRNord
+- **Created:** 2018-05-05T23:01:20Z
+- **Branch:** develop → master
+- **Merged:** 2018-05-05T23:09:51Z
+- **Labels:** enhancement
+- **Assignees:** @MTRNord
+- **Diff:** [6.diff](./6.diff)
+
+---
+
+Still todo is interface to json processing
+
diff --git a/pulls/7.diff b/pulls/7.diff
@@ -0,0 +1,1269 @@
+diff --git a/Gopkg.lock b/Gopkg.lock
+index 7859130..629ec69 100644
+--- a/Gopkg.lock
++++ b/Gopkg.lock
+@@ -13,6 +13,12 @@
+ packages = ["."]
+ revision = "a7fc80c8060c2544fe5d4dae465b584f8e9b4e27"
+
++[[projects]]
++ name = "github.com/mattn/go-sqlite3"
++ packages = ["."]
++ revision = "6c771bb9887719704b210e87e934f08be014bdb1"
++ version = "v1.6.0"
++
+ [[projects]]
+ branch = "master"
+ name = "github.com/shibukawa/configdir"
+@@ -34,6 +40,6 @@
+ [solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+- inputs-digest = "c22db96d1e74b32e9427a6f762b2be5797dcc8426407dc4769795fe6ca7296be"
++ inputs-digest = "f746b36e895639f6b0cbe2cb4d928637d254f83f60346a95eaf5c0f383683229"
+ solver-name = "gps-cdcl"
+ solver-version = 1
+diff --git a/cmd/root.go b/cmd/root.go
+index 148f65a..9b10937 100644
+--- a/cmd/root.go
++++ b/cmd/root.go
+@@ -19,7 +19,8 @@ import (
+ "os"
+
+ "github.com/Nordgedanken/Morpheusv2/pkg/app"
+- dbImpl "github.com/Nordgedanken/Morpheusv2/pkg/db/implementation"
++ "github.com/Nordgedanken/Morpheusv2/pkg/db/sqlite"
++ "github.com/Nordgedanken/Morpheusv2/pkg/util"
+ "github.com/shibukawa/configdir"
+ "github.com/spf13/cobra"
+ "io"
+@@ -47,7 +48,7 @@ var rootCmd = &cobra.Command{
+ }
+
+ // os.OpenFile opens the file where the log is supposed to be written to
+- logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
++ logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0600)
+ if err != nil {
+ return err
+ }
+@@ -59,7 +60,8 @@ var rootCmd = &cobra.Command{
+ log.SetOutput(mw)
+
+ // dbImpl.Init() generates the needed tables if needed before the app starts
+- err = dbImpl.Init()
++ util.DB = &sqlite.SQLite{}
++ err = util.DB.Init()
+ if err != nil {
+ return err
+ }
+diff --git a/pkg/app/main.go b/pkg/app/main.go
+index 3832900..255f074 100644
+--- a/pkg/app/main.go
++++ b/pkg/app/main.go
+@@ -15,7 +15,10 @@
+ package app
+
+ import (
++ "database/sql"
++ "github.com/Nordgedanken/Morpheusv2/pkg/loginUI"
+ "github.com/Nordgedanken/Morpheusv2/pkg/mainUI"
++ "github.com/Nordgedanken/Morpheusv2/pkg/util"
+ "github.com/matrix-org/gomatrix"
+ "github.com/therecipe/qt/core"
+ "github.com/therecipe/qt/gui"
+@@ -36,11 +39,20 @@ func Start(argsArg []string) error {
+
+ initApp()
+
+- mainUIS := mainUI.NewMainUI(windowWidth, windowHeight, window)
+- SetNewWindow(mainUIS, window)
++ _, err := util.DB.GetCurrentUser()
++ // We special case ErrNoRows because this is expected to happen if user is missing
++ if err == sql.ErrNoRows {
++ loginUIs := loginUI.NewLoginUI(windowWidth, windowHeight, window)
++ SetNewWindow(loginUIs, window)
++ } else if err != nil {
++ return err
++ } else {
++ mainUIs := mainUI.NewMainUI(windowWidth, windowHeight, window)
++ SetNewWindow(mainUIs, window)
++ }
+
+ widgets.QApplication_Exec()
+-
++
+ return nil
+ }
+
+@@ -65,7 +77,7 @@ func initApp() {
+ window.Resize2(windowWidth, windowHeight)
+ window.Move2(windowX, windowY)
+
+- app.ConnectQuit(func() {
++ window.ConnectCloseEvent(func(event *gui.QCloseEvent) {
+ log.Println("Morpheus closed")
+ })
+
+diff --git a/pkg/app/ui.go b/pkg/app/ui.go
+index 37ced17..7273079 100644
+--- a/pkg/app/ui.go
++++ b/pkg/app/ui.go
+@@ -1,3 +1,17 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
+ package app
+
+ import (
+diff --git a/pkg/db/db.go b/pkg/db/db.go
+index 0ffaede..27f04b8 100644
+--- a/pkg/db/db.go
++++ b/pkg/db/db.go
+@@ -1,14 +1,37 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
+ package db
+
+-import "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++import (
++ "database/sql"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++)
+
+ // DB defines a Interface to allow multiple DB Implementations
+ type DB interface {
++ Init() error
++ Open() *sql.DB
++
+ SaveRoom(Room matrix.Room) error
+- GetRooms() (rooms map[string]matrix.Room, err error)
+- GetRoom(roomID string) (room matrix.Room, err error)
++ GetRooms() (roomsR []matrix.Room, err error)
++ GetRoom(roomID string) (roomR matrix.Room, err error)
+
+ SaveUser(user matrix.User) error
+- GetUsers() (map[string]matrix.User, error)
+- GetCurrentUser() (matrix.User, error)
++ GetUser(userID string) (userR matrix.User, err error)
++ GetCurrentUser() (userR matrix.User, err error)
++
++ SaveMessage(message matrix.Message) error
++ GetMessage(eventID string) (messageR matrix.Message, err error)
+ }
+diff --git a/pkg/db/sqlite/db.go b/pkg/db/sqlite/db.go
+new file mode 100644
+index 0000000..fa80421
+--- /dev/null
++++ b/pkg/db/sqlite/db.go
+@@ -0,0 +1,62 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package sqlite
++
++import (
++ "database/sql"
++ "fmt"
++ _ "github.com/mattn/go-sqlite3" // Go-sqlite3 side effect import needed to use SQLite3 databases
++ "github.com/shibukawa/configdir"
++ "log"
++ "path/filepath"
++)
++
++// Init prepares the DB by opening it and creating the required tables if needed
++func (s *SQLite) Init() (err error) {
++ log.Println("Start setting up DB")
++ var openErr error
++
++ // Open the data.db file. It will be created if it doesn't exist.
++ configDirs := configdir.New("Nordgedanken", "Morpheusv2")
++ filePath := filepath.ToSlash(configDirs.QueryFolders(configdir.Global)[0].Path)
++
++ log.Println("DBFilePath: ", filePath+"/data.db")
++ s.db, openErr = sql.Open("sqlite3", filePath+"/data.db")
++ if openErr != nil {
++ err = openErr
++ return
++ }
++
++ log.Println("Creating DB Tables if needed")
++ createTables := `CREATE TABLE IF NOT EXISTS users (id varchar not null primary key, display_name text, avatar text, access_token text, own integer);
++ CREATE TABLE IF NOT EXISTS messages (id varchar not null primary key, author_id varchar, message text, timestamp datetime, pure_event text);
++ CREATE TABLE IF NOT EXISTS rooms (id varchar not null primary key, room_aliases text, room_name text, room_avatar text, room_topic text, room_messages text);
++ `
++ _, execErr := s.db.Exec(createTables)
++ if execErr != nil {
++ err = fmt.Errorf("DB EXEC ERR: %s", execErr)
++ return
++ }
++ log.Println("Finished setting DB Setup")
++ return
++}
++
++// Open returns the in Init() created db variable
++func (s *SQLite) Open() *sql.DB {
++ if s.db != nil {
++ return s.db
++ }
++ return nil
++}
+diff --git a/pkg/db/sqlite/messages.go b/pkg/db/sqlite/messages.go
+new file mode 100644
+index 0000000..6b709d7
+--- /dev/null
++++ b/pkg/db/sqlite/messages.go
+@@ -0,0 +1,93 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package sqlite
++
++import (
++ "encoding/json"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix/messages"
++ "github.com/matrix-org/gomatrix"
++ "time"
++)
++
++// SaveMessage saves message Events to the DB
++func (s *SQLite) SaveMessage(message matrix.Message) error {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ tx, err := s.db.Begin()
++ if err != nil {
++ return err
++ }
++
++ stmt, err := tx.Prepare("INSERT INTO messages (id, author_id, message, timestamp, pure_event) VALUES (?, ?, ?, ?, ?)")
++ if err != nil {
++ return err
++ }
++ defer stmt.Close()
++
++ id := message.GetEventID()
++ authorID := message.GetAuthorMXID()
++ messageS := message.GetMessage()
++ timestampR := message.GetTimestamp()
++ timestamp := timestampR.Format("2006-01-02 15:04:05")
++ pureEvent := message.GetEvent()
++ _, err = stmt.Exec(id, authorID, messageS, timestamp, pureEvent)
++ if err != nil {
++ return err
++ }
++
++ return tx.Commit()
++}
++
++// GetMessage returns the Message where the id matches the eventID
++func (s *SQLite) GetMessage(eventID string) (messageR matrix.Message, err error) {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ stmt, err := s.db.Prepare(`SELECT author_id, message, timestamp, pure_event FROM messages WHERE id=$1`)
++ if err != nil {
++ return
++ }
++ defer stmt.Close()
++
++ row := stmt.QueryRow(eventID)
++
++ var authorID string
++ var messageS string
++ var timestamp time.Time
++ var pureEvent string
++ err = row.Scan(&authorID, &messageS, ×tamp, &pureEvent)
++ if err != nil {
++ return
++ }
++
++ messageI := &messages.Message{}
++ messageI.SetEventID(eventID)
++ messageI.SetAuthorMXID(authorID)
++ messageI.SetMessage(messageS)
++ messageI.SetTimestamp(×tamp)
++ var gomatrixEvent gomatrix.Event
++ err = json.Unmarshal([]byte(pureEvent), &gomatrixEvent)
++ if err != nil {
++ return
++ }
++ messageI.SetEvent(&gomatrixEvent)
++
++ messageR = messageI
++ return
++}
+diff --git a/pkg/db/sqlite/rooms.go b/pkg/db/sqlite/rooms.go
+new file mode 100644
+index 0000000..1bfd627
+--- /dev/null
++++ b/pkg/db/sqlite/rooms.go
+@@ -0,0 +1,172 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package sqlite
++
++import (
++ "encoding/json"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix/rooms"
++)
++
++// SaveRoom saves a Room into the sqlite DB
++func (s *SQLite) SaveRoom(Room matrix.Room) error {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ tx, err := s.db.Begin()
++ if err != nil {
++ return err
++ }
++
++ stmt, err := tx.Prepare("INSERT INTO rooms (room_aliases, id, room_name, room_avatar, room_topic, room_messages) VALUES (?, ?, ?, ?, ?, ?)")
++ if err != nil {
++ return err
++ }
++ defer stmt.Close()
++
++ aliases := Room.GetRoomAliases()
++ aliasesBytes, err := json.Marshal(aliases)
++ if err != nil {
++ return err
++ }
++ aliasesS := string(aliasesBytes)
++ roomID := Room.GetRoomID()
++ name, err := Room.GetName()
++ if err != nil {
++ return err
++ }
++ avatar, err := Room.GetAvatar()
++ if err != nil {
++ return err
++ }
++ topic, err := Room.GetTopic()
++ if err != nil {
++ return err
++ }
++
++ messages := Room.GetMessages()
++ if err != nil {
++ return err
++ }
++ var messageIDs []string
++ for _, v := range messages {
++ messageIDs = append(messageIDs, v.GetEventID())
++ }
++
++ _, err = stmt.Exec(aliasesS, roomID, name, string(avatar), topic, messageIDs)
++ if err != nil {
++ return err
++ }
++ return tx.Commit()
++}
++
++// GetRooms returns all Rooms from the Database
++func (s *SQLite) GetRooms() (roomsR []matrix.Room, err error) {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ rows, err := s.db.Query("SELECT id, room_aliases, room_name, room_avatar, room_topic, room_messages FROM rooms")
++ if err != nil {
++ return
++ }
++ defer rows.Close()
++
++ for rows.Next() {
++ var roomID string
++ var roomAliases string
++ var roomName string
++ var roomAvatar string
++ var roomTopic string
++ var roomMessages string
++ err = rows.Scan(&roomID, &roomAliases, &roomName, &roomAvatar, &roomTopic, &roomMessages)
++ if err != nil {
++ return
++ }
++
++ roomI := &rooms.Room{}
++ roomI.SetRoomID(roomID)
++ var aliases []string
++ err = json.Unmarshal([]byte(roomAliases), &aliases)
++ if err != nil {
++ return
++ }
++ roomI.SetRoomAliases(aliases)
++ roomI.SetName(roomName)
++ roomI.SetAvatar([]byte(roomAvatar))
++ roomI.SetTopic(roomTopic)
++ var messageIDs []string
++ err = json.Unmarshal([]byte(roomMessages), &messageIDs)
++ if err != nil {
++ return
++ }
++ // TODO Convert IDs to messages slice using another call or from the beginning on using a JOIN
++ //roomI.SetMessages(messages)
++
++ roomsR = append(roomsR, roomI)
++ }
++
++ // get any error encountered during iteration
++ err = rows.Err()
++ return
++}
++
++// GetRoom returns the Room where the id matches the roomID
++func (s *SQLite) GetRoom(roomID string) (roomR matrix.Room, err error) {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ stmt, err := s.db.Prepare(`SELECT room_aliases, room_name, room_avatar, room_topic, room_messages FROM rooms WHERE id=$1`)
++ if err != nil {
++ return
++ }
++ defer stmt.Close()
++
++ row := stmt.QueryRow(roomID)
++
++ var roomAliases string
++ var roomName string
++ var roomAvatar string
++ var roomTopic string
++ var roomMessages string
++ err = row.Scan(&roomAliases, &roomName, &roomAvatar, &roomTopic, &roomMessages)
++ if err != nil {
++ return
++ }
++
++ roomI := &rooms.Room{}
++ roomI.SetRoomID(roomID)
++ var aliases []string
++ err = json.Unmarshal([]byte(roomAliases), &aliases)
++ if err != nil {
++ return
++ }
++ roomI.SetRoomAliases(aliases)
++ roomI.SetName(roomName)
++ roomI.SetAvatar([]byte(roomAvatar))
++ roomI.SetTopic(roomTopic)
++ var messageIDs []string
++ err = json.Unmarshal([]byte(roomMessages), &messageIDs)
++ if err != nil {
++ return
++ }
++ // TODO Convert IDs to messages slice using another call or from the beginning on using a JOIN
++ //roomI.SetMessages(messages)
++
++ roomR = roomI
++ return
++}
+diff --git a/pkg/db/sqlite/struct.go b/pkg/db/sqlite/struct.go
+new file mode 100644
+index 0000000..6497773
+--- /dev/null
++++ b/pkg/db/sqlite/struct.go
+@@ -0,0 +1,22 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package sqlite
++
++import "database/sql"
++
++// SQLite implements a SQLite database for the db.DB interface
++type SQLite struct {
++ db *sql.DB
++}
+diff --git a/pkg/db/sqlite/users.go b/pkg/db/sqlite/users.go
+new file mode 100644
+index 0000000..e78a6a6
+--- /dev/null
++++ b/pkg/db/sqlite/users.go
+@@ -0,0 +1,125 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package sqlite
++
++import (
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix/users"
++ "github.com/matrix-org/gomatrix"
++ "strings"
++)
++
++// SaveUser saves a matrix User to the User table
++func (s *SQLite) SaveUser(user matrix.User) error {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ tx, err := s.db.Begin()
++ if err != nil {
++ return err
++ }
++
++ stmt, err := tx.Prepare("INSERT INTO users (id, display_name, avatar) VALUES (?, ?, ?)")
++ if err != nil {
++ return err
++ }
++ defer stmt.Close()
++ displayName, err := user.GetDisplayName("")
++ if err != nil {
++ return err
++ }
++ avatar, err := user.GetAvatar("")
++ if err != nil {
++ return err
++ }
++ mxid := user.GetMXID()
++ _, err = stmt.Exec(mxid, displayName, string(avatar))
++ if err != nil {
++ return err
++ }
++
++ return tx.Commit()
++}
++
++// GetCurrentUser returns the current user including a ready gomatrix client
++func (s *SQLite) GetCurrentUser() (userR matrix.User, err error) {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ stmt, err := s.db.Prepare(`SELECT id, display_name, avatar, access_token FROM users WHERE own=1`)
++ if err != nil {
++ return
++ }
++ defer stmt.Close()
++
++ row := stmt.QueryRow()
++
++ var mxid string
++ var displayName string
++ var avatar string
++ var accessToken string
++ err = row.Scan(&mxid, &displayName, &avatar, &accessToken)
++ if err != nil {
++ return
++ }
++
++ userI := &users.User{}
++ userI.SetMXID(mxid)
++ userI.SetDisplayName("", displayName)
++ userI.SetAvatar("", []byte(avatar))
++
++ splitUser := strings.Split(mxid, ":")
++ domain := strings.TrimPrefix(mxid, splitUser[0]+":")
++ client, err := gomatrix.NewClient(domain, mxid, accessToken)
++ if err != nil {
++ return
++ }
++ userI.SetCli(client)
++
++ userR = userI
++ return
++}
++
++// GetUser returns a user matching the mxid of the argument
++func (s *SQLite) GetUser(userID string) (userR matrix.User, err error) {
++ if s.db == nil {
++ s.db = s.Open()
++ }
++
++ stmt, err := s.db.Prepare(`SELECT display_name, avatar FROM users WHERE id=$1`)
++ if err != nil {
++ return
++ }
++ defer stmt.Close()
++
++ row := stmt.QueryRow(userID)
++
++ var displayName string
++ var avatar string
++ err = row.Scan(&displayName, &avatar)
++ if err != nil {
++ return
++ }
++
++ userI := &users.User{}
++ userI.SetMXID(userID)
++ userI.SetDisplayName("", displayName)
++ userI.SetAvatar("", []byte(avatar))
++
++ userR = userI
++ return
++}
+diff --git a/pkg/loginUI/loginUI.go b/pkg/loginUI/loginUI.go
+new file mode 100644
+index 0000000..fa3d993
+--- /dev/null
++++ b/pkg/loginUI/loginUI.go
+@@ -0,0 +1,77 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package loginUI
++
++import (
++ "github.com/matrix-org/gomatrix"
++ "github.com/therecipe/qt/core"
++ "github.com/therecipe/qt/gui"
++ "github.com/therecipe/qt/uitools"
++ "github.com/therecipe/qt/widgets"
++)
++
++// LoginUI defines the data for the login ui
++type LoginUI struct {
++ widget *widgets.QWidget
++ cli *gomatrix.Client
++ window *widgets.QMainWindow
++ windowWidth int
++ windowHeight int
++}
++
++// NewLoginUI gives you a MainUI struct with profiled data
++func NewLoginUI(windowWidth, windowHeight int, window *widgets.QMainWindow) (loginUI *LoginUI) {
++ loginUI = &LoginUI{
++ windowWidth: windowWidth,
++ windowHeight: windowHeight,
++ window: window,
++ }
++ return
++}
++
++// SetCli sets the gomatrix Client for the LoginUI
++func (m *LoginUI) SetCli(cli *gomatrix.Client) {
++ m.cli = cli
++}
++
++// GetWidget returns the QWidget of the LoginUI
++func (m *LoginUI) GetWidget() (widget *widgets.QWidget) {
++ return m.widget
++}
++
++// NewUI prepares the new UI
++func (m *LoginUI) NewUI() error {
++ m.widget = widgets.NewQWidget(nil, 0)
++
++ var loader = uitools.NewQUiLoader(nil)
++ var file = core.NewQFile2(":/qml/ui/login.ui")
++
++ file.Open(core.QIODevice__ReadOnly)
++ mainWidget := loader.Load(file, m.widget)
++ file.Close()
++
++ var layout = widgets.NewQHBoxLayout()
++ m.window.SetLayout(layout)
++ layout.InsertWidget(0, mainWidget, 0, core.Qt__AlignTop|core.Qt__AlignLeft)
++ layout.SetSpacing(0)
++ layout.SetContentsMargins(0, 0, 0, 0)
++
++ m.widget.ConnectResizeEvent(func(event *gui.QResizeEvent) {
++ mainWidget.Resize(event.Size())
++ event.Accept()
++ })
++
++ return nil
++}
+diff --git a/pkg/mainUI/mainUI.go b/pkg/mainUI/mainUI.go
+index 7fcaaf9..a8cddc3 100644
+--- a/pkg/mainUI/mainUI.go
++++ b/pkg/mainUI/mainUI.go
+@@ -1,3 +1,17 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
+ package mainUI
+
+ import (
+diff --git a/pkg/matrix/dataTypes.go b/pkg/matrix/dataTypes.go
+index 8d30e68..a010373 100644
+--- a/pkg/matrix/dataTypes.go
++++ b/pkg/matrix/dataTypes.go
+@@ -1,3 +1,17 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
+ package matrix
+
+ import (
+@@ -9,8 +23,15 @@ import (
+ type User interface {
+ SetCli(cli *gomatrix.Client)
+ SetMXID(id string)
++ SetDisplayName(roomID string, name string)
++ SetAvatar(roomID string, avatar []byte)
++
++ GetMXID() string
+ GetDisplayName(roomID string) (string, error)
+- GetAvatar(roomID string) (string, error)
++ GetAvatar(roomID string) ([]byte, error)
++ GetCli() (cli *gomatrix.Client)
++
++ //Implement MarshalJSON() (b []byte, e error) as in http://gregtrowbridge.com/golang-json-serialization-with-interfaces/ to support json
+ }
+
+ // Room defines a Interface to allow multiple Room type Implementations
+@@ -18,11 +39,20 @@ type Room interface {
+ // Handled using global "own User"
+ //SetCli(cli *gomatrix.Client)
+ SetRoomID(id string)
+- SetRoomAliases(aliases map[int64]string)
++ SetRoomAliases(aliases []string)
++ SetName(name string)
++ SetAvatar(avatar []byte)
++ SetTopic(topic string)
++ SetMessages(messages []Message)
++
++ GetRoomID() string
++ GetRoomAliases() []string
+ GetName() (string, error)
+- GetAvatar() (string, error)
++ GetAvatar() ([]byte, error)
+ GetTopic() (string, error)
+- GetMessages() (map[string]Message, error)
++ GetMessages() []Message
++
++ //Implement MarshalJSON() (b []byte, e error) as in http://gregtrowbridge.com/golang-json-serialization-with-interfaces/ to support json
+ }
+
+ // Message defines a Interface to allow multiple Message type Implementations
+@@ -34,5 +64,14 @@ type Message interface {
+ SetAuthorMXID(mxid string)
+ SetMessage(message string)
+ SetTimestamp(ts *time.Time)
++
++ GetEventID() (id string)
++ GetEvent() (event *gomatrix.Event)
++ GetAuthorMXID() (mxid string)
++ GetMessage() (message string)
++ GetTimestamp() (ts *time.Time)
++
+ Show() error
++
++ //Implement MarshalJSON() (b []byte, e error) as in http://gregtrowbridge.com/golang-json-serialization-with-interfaces/ to support json
+ }
+diff --git a/pkg/matrix/messages/message.go b/pkg/matrix/messages/message.go
+new file mode 100644
+index 0000000..186fdda
+--- /dev/null
++++ b/pkg/matrix/messages/message.go
+@@ -0,0 +1,85 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package messages
++
++import (
++ "github.com/matrix-org/gomatrix"
++ "time"
++)
++
++// Message holds the needed Message data and allows to work with that. It gets normally loaded from the cache
++type Message struct {
++ eventID string
++ event *gomatrix.Event
++ authorID string
++ text string
++ timestamp *time.Time
++}
++
++// SetEventID adds the eventID to the current Message
++func (m *Message) SetEventID(id string) {
++ m.eventID = id
++}
++
++// SetEvent adds the gomatrix Event to the current Message
++func (m *Message) SetEvent(event *gomatrix.Event) {
++ m.event = event
++}
++
++// SetAuthorMXID adds the author MXID to the current Message
++func (m *Message) SetAuthorMXID(mxid string) {
++ m.authorID = mxid
++}
++
++// SetMessage adds the message Text to the current Message
++func (m *Message) SetMessage(message string) {
++ m.text = message
++}
++
++// SetTimestamp adds the Timestamp to the current Message
++func (m *Message) SetTimestamp(ts *time.Time) {
++ m.timestamp = ts
++}
++
++// GetEventID returns the event ID from the current Message
++func (m *Message) GetEventID() (id string) {
++ return m.eventID
++}
++
++// GetEvent returns the gomatrix event from the current Message
++func (m *Message) GetEvent() (event *gomatrix.Event) {
++ return m.event
++}
++
++// GetAuthorMXID returns the authors mxid from the current Message
++func (m *Message) GetAuthorMXID() (mxid string) {
++ return m.authorID
++}
++
++// GetMessage returns the text from the current Message
++func (m *Message) GetMessage() (message string) {
++ return m.text
++}
++
++// GetTimestamp returns the timestamp from the current Message
++func (m *Message) GetTimestamp() (ts *time.Time) {
++ return m.timestamp
++}
++
++// Show adds the current Message to the UI
++// TODO implement it
++func (m *Message) Show() error {
++ return nil
++}
+diff --git a/pkg/matrix/rooms/room.go b/pkg/matrix/rooms/room.go
+new file mode 100644
+index 0000000..9d884ce
+--- /dev/null
++++ b/pkg/matrix/rooms/room.go
+@@ -0,0 +1,145 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package rooms
++
++import (
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++ "github.com/Nordgedanken/Morpheusv2/pkg/util"
++ "github.com/matrix-org/gomatrix"
++ "strings"
++)
++
++// Room holds the needed Room data and allows to work with that. It gets normally loaded from the cache
++type Room struct {
++ id string
++ aliases []string
++ name string
++ avatar []byte
++ topic string
++ messages []matrix.Message
++}
++
++// SetRoomID adds the roomID to the current Room
++func (r *Room) SetRoomID(id string) {
++ r.id = id
++}
++
++// SetRoomAliases adds the aliases to the current Room
++func (r *Room) SetRoomAliases(aliases []string) {
++ r.aliases = aliases
++}
++
++// SetName adds the name to the current Room
++func (r *Room) SetName(name string) {
++ r.name = name
++}
++
++// SetAvatar adds the avatar to the current Room
++func (r *Room) SetAvatar(avatar []byte) {
++ r.avatar = avatar
++}
++
++// SetTopic adds the topic to the current Room
++func (r *Room) SetTopic(topic string) {
++ r.topic = topic
++}
++
++// SetMessages adds the messages to the current Room
++func (r *Room) SetMessages(messages []matrix.Message) {
++ r.messages = messages
++}
++
++// GetRoomID returns the room ID from the current Room
++func (r *Room) GetRoomID() string {
++ return r.id
++}
++
++// GetRoomAliases returns the room aliases from the current Room
++func (r *Room) GetRoomAliases() []string {
++ return r.aliases
++}
++
++// GetName returns the name from the current Room
++func (r *Room) GetName() (string, error) {
++ if r.name == "" {
++ type RespRoomName struct {
++ Name string `json:"name"`
++ }
++ resp := &RespRoomName{}
++ err := util.User.GetCli().StateEvent(r.id, "m.room.name", "", resp)
++ if err != nil {
++ return "", err
++ }
++ r.name = resp.Name
++ }
++ return r.name, nil
++}
++
++// GetAvatar returns the avatar from the current Room
++func (r *Room) GetAvatar() ([]byte, error) {
++ if r.avatar == nil {
++ resp := &gomatrix.Event{}
++ err := util.User.GetCli().StateEvent(r.id, "m.room.avatar", "", resp)
++ if err != nil {
++ return nil, err
++ }
++ var avatar []byte
++ value, exists := resp.Content["url"]
++ if !exists {
++ return nil, nil
++ }
++ url, ok := value.(string)
++ if !ok {
++ return nil, nil
++ }
++ split := strings.Split(url, "/")
++ servername := strings.TrimPrefix(split[0], "mxc://")
++ mediaID := split[1]
++ mediaURL := util.User.GetCli().BuildBaseURL("_matrix/media/r0/download", servername, mediaID)
++ avatar, err = util.User.GetCli().MakeRequest("GET", mediaURL, nil, nil)
++ if err != nil {
++ return nil, err
++ }
++ r.avatar = avatar
++ }
++ return r.avatar, nil
++}
++
++// GetTopic returns the topic from the current Room
++func (r *Room) GetTopic() (string, error) {
++ if r.topic == "" {
++ resp := &gomatrix.Event{}
++ err := util.User.GetCli().StateEvent(r.id, "m.room.topic", "", resp)
++ if err != nil {
++ return "", err
++ }
++ value, exists := resp.Content["topic"]
++ if !exists {
++ return "", nil
++ }
++ topic, ok := value.(string)
++ if !ok {
++ return "", nil
++ }
++ r.topic = topic
++ }
++ return r.topic, nil
++}
++
++// GetMessages returns the messages from the current Room
++func (r *Room) GetMessages() []matrix.Message {
++ // TODO Lazy load from DB
++ return r.messages
++}
+diff --git a/pkg/matrix/users/user.go b/pkg/matrix/users/user.go
+new file mode 100644
+index 0000000..8cee5cf
+--- /dev/null
++++ b/pkg/matrix/users/user.go
+@@ -0,0 +1,127 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package users
++
++import (
++ "github.com/Nordgedanken/Morpheusv2/pkg/util"
++ "github.com/matrix-org/gomatrix"
++ "strings"
++)
++
++// User holds the needed User data and allows to work with that. It gets normally loaded from the cache
++type User struct {
++ cli *gomatrix.Client
++ mxid string
++ defaultDisplayName string
++ displayName map[string]string
++ defaultAvatar []byte
++ avatar map[string][]byte
++}
++
++// SetCli adds the gomatrix.Client to the current User. This only happens if the User is the current User aka the one that logged into the client.
++func (u *User) SetCli(cli *gomatrix.Client) {
++ u.cli = cli
++}
++
++// SetMXID adds the mxid to the current User
++func (u *User) SetMXID(id string) {
++ u.mxid = id
++}
++
++// SetDisplayName adds the displayName to the current User
++func (u *User) SetDisplayName(roomID string, name string) {
++ if roomID == "" {
++ u.defaultDisplayName = name
++ } else {
++ if u.displayName == nil {
++ u.displayName = make(map[string]string)
++ }
++ u.displayName[roomID] = name
++ }
++}
++
++// SetAvatar adds the avatar to the current User
++func (u *User) SetAvatar(roomID string, avatar []byte) {
++ if roomID == "" {
++ u.defaultAvatar = avatar
++ } else {
++ if u.avatar == nil {
++ u.avatar = make(map[string][]byte)
++ }
++ u.avatar[roomID] = avatar
++ }
++}
++
++// GetMXID returns the mxid from the current User
++func (u *User) GetMXID() string {
++ return u.mxid
++}
++
++// GetDisplayName returns the displayName from the current User
++func (u *User) GetDisplayName(roomID string) (string, error) {
++ if roomID == "" {
++ if u.defaultDisplayName == "" {
++ resp, err := util.User.GetCli().GetDisplayName(u.mxid)
++ if err != nil {
++ return "", err
++ }
++ u.defaultDisplayName = resp.DisplayName
++ }
++ return u.defaultDisplayName, nil
++ }
++ // TODO get Membership Event from Room instead returning default directly
++ if u.displayName[roomID] == "" {
++ return u.defaultDisplayName, nil
++ }
++ return u.displayName[roomID], nil
++}
++
++// GetAvatar returns the avatar from the current User
++func (u *User) GetAvatar(roomID string) ([]byte, error) {
++ if roomID == "" {
++ if u.defaultAvatar == nil {
++ urlPath := util.User.GetCli().BuildURL("profile", u.mxid, "avatar_url")
++ s := struct {
++ AvatarURL string `json:"avatar_url"`
++ }{}
++
++ _, err := util.User.GetCli().MakeRequest("GET", urlPath, nil, &s)
++ if err != nil {
++ return nil, err
++ }
++
++ split := strings.Split(s.AvatarURL, "/")
++ servername := strings.TrimPrefix(split[0], "mxc://")
++ mediaID := split[1]
++ mediaURL := util.User.GetCli().BuildBaseURL("_matrix/media/r0/download", servername, mediaID)
++ avatar, err := util.User.GetCli().MakeRequest("GET", mediaURL, nil, nil)
++ if err != nil {
++ return nil, err
++ }
++ u.defaultAvatar = avatar
++ }
++ return u.defaultAvatar, nil
++ }
++ // TODO get Membership Event from Room instead returning default directly
++ if u.avatar[roomID] == nil {
++ return u.defaultAvatar, nil
++ }
++ return u.avatar[roomID], nil
++}
++
++// GetCli returns the gomatrix.Client from the current User
++func (u *User) GetCli() *gomatrix.Client {
++ return u.cli
++}
+diff --git a/pkg/util/vars.go b/pkg/util/vars.go
+new file mode 100644
+index 0000000..7325755
+--- /dev/null
++++ b/pkg/util/vars.go
+@@ -0,0 +1,26 @@
++// Copyright © 2018 MTRNord <info@nordgedanken.de>
++//
++// 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.
++
++package util
++
++import (
++ "github.com/Nordgedanken/Morpheusv2/pkg/db"
++ "github.com/Nordgedanken/Morpheusv2/pkg/matrix"
++)
++
++// DB holds the main pointer to the Database
++var DB db.DB
++
++// User holds the Current User
++var User matrix.User
diff --git a/pulls/7.json b/pulls/7.json
@@ -0,0 +1,18 @@
+{
+ "number": 7,
+ "title": "Merge master back into develop",
+ "state": "merged",
+ "diff_file": "7.diff",
+ "author": "MTRNord",
+ "created_at": "2018-05-05T23:12:22Z",
+ "closed_at": "2018-05-05T23:12:38Z",
+ "merged_at": "2018-05-05T23:12:38Z",
+ "base_ref": "develop",
+ "head_ref": "master",
+ "labels": [],
+ "assignees": [],
+ "requested_reviewers": [],
+ "body": "",
+ "comments": [],
+ "review_comments": []
+}
diff --git a/pulls/7.md b/pulls/7.md
@@ -0,0 +1,13 @@
+# PR #7 Merge master back into develop
+
+- **Status:** merged
+- **Author:** @MTRNord
+- **Created:** 2018-05-05T23:12:22Z
+- **Branch:** master → develop
+- **Merged:** 2018-05-05T23:12:38Z
+- **Diff:** [7.diff](./7.diff)
+
+---
+
+_No description._
+
diff --git a/pulls/8.diff b/pulls/8.diff
@@ -0,0 +1,70 @@
+diff --git a/pkg/app/main.go b/pkg/app/main.go
+index 255f074..3b7aa0e 100644
+--- a/pkg/app/main.go
++++ b/pkg/app/main.go
+@@ -52,7 +52,7 @@ func Start(argsArg []string) error {
+ }
+
+ widgets.QApplication_Exec()
+-
++
+ return nil
+ }
+
+diff --git a/pkg/db/implementation/db.go b/pkg/db/implementation/db.go
+deleted file mode 100644
+index 9429d4b..0000000
+--- a/pkg/db/implementation/db.go
++++ /dev/null
+@@ -1,51 +0,0 @@
+-package implementation
+-
+-import (
+- "database/sql"
+- "fmt"
+- _ "github.com/mattn/go-sqlite3" // Go-sqlite3 side effect import needed to use SQLite3 databases
+- "github.com/shibukawa/configdir"
+- "log"
+- "path/filepath"
+-)
+-
+-var db *sql.DB
+-
+-// Init prepares the DB by opening it and creating the required tables if needed
+-// TODO: Make part of the interface
+-func Init() (err error) {
+- log.Println("Start setting up DB")
+- var openErr error
+-
+- // Open the data.db file. It will be created if it doesn't exist.
+- configDirs := configdir.New("Nordgedanken", "Morpheusv2")
+- filePath := filepath.ToSlash(configDirs.QueryFolders(configdir.Global)[0].Path)
+-
+- log.Println("DBFilePath: ", filePath+"/data.db")
+- db, openErr = sql.Open("sqlite3", filePath+"/data.db")
+- if openErr != nil {
+- err = openErr
+- return
+- }
+-
+- log.Println("Creating DB Tables if needed")
+- createTables := `CREATE TABLE IF NOT EXISTS users (id integer not null primary key, display_name text, avatar text);
+- CREATE TABLE IF NOT EXISTS messages (id integer not null primary key, author text, message text, timestamp text, pure_event text);
+- CREATE TABLE IF NOT EXISTS rooms (id integer not null primary key, room_aliases text, room_id text, room_name text, room_avatar text, room_topic text, room_messages text);
+- `
+- _, execErr := db.Exec(createTables)
+- if execErr != nil {
+- err = fmt.Errorf("DB EXEC ERR: %s", execErr)
+- return
+- }
+- log.Println("Finished setting DB Setup")
+- return
+-}
+-
+-// Open returns the in Init() created db variable
+-func Open() *sql.DB {
+- if db != nil {
+- return db
+- }
+- return nil
+-}
diff --git a/pulls/8.json b/pulls/8.json
@@ -0,0 +1,20 @@
+{
+ "number": 8,
+ "title": "Remove weird whitespace and cleanup Code",
+ "state": "merged",
+ "diff_file": "8.diff",
+ "author": "MTRNord",
+ "created_at": "2018-05-05T23:18:23Z",
+ "closed_at": "2018-05-05T23:18:31Z",
+ "merged_at": "2018-05-05T23:18:31Z",
+ "base_ref": "master",
+ "head_ref": "develop",
+ "labels": [
+ "enhancement"
+ ],
+ "assignees": [],
+ "requested_reviewers": [],
+ "body": "",
+ "comments": [],
+ "review_comments": []
+}
diff --git a/pulls/8.md b/pulls/8.md
@@ -0,0 +1,14 @@
+# PR #8 Remove weird whitespace and cleanup Code
+
+- **Status:** merged
+- **Author:** @MTRNord
+- **Created:** 2018-05-05T23:18:23Z
+- **Branch:** develop → master
+- **Merged:** 2018-05-05T23:18:31Z
+- **Labels:** enhancement
+- **Diff:** [8.diff](./8.diff)
+
+---
+
+_No description._
+