Skip to content

Commit

Permalink
Merge branch 'master' into dependabot/hex/credo-1.7.10
Browse files Browse the repository at this point in the history
  • Loading branch information
JannikStreek authored Nov 20, 2024
2 parents ee5a085 + 49d8ab7 commit daedcc9
Show file tree
Hide file tree
Showing 42 changed files with 413 additions and 689 deletions.
82 changes: 38 additions & 44 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,39 +20,15 @@ import "phoenix_html"
import { Socket } from "phoenix"
import NProgress from "nprogress"
import { LiveSocket } from "phoenix_live_view"
import QRCodeStyling from "qr-code-styling";
import ClipboardJS from "clipboard"
import { buildQrCodeOptions } from "./qrCodeUtils.js"
import { appendQrCode, initQrDownload } from "./qrCodeUtils.js"
import { initShareButtonClickHandler } from "./shareUtils.js"

let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")

let Hooks = {}
const sortables = [];

Hooks.CopyBrainstormingLinkButton = {
mounted() {
new ClipboardJS(this.el);
}
}

Hooks.NativeSharingButton = {
mounted() {
const shareData = {
title: this.el.getAttribute(`data-native-sharing-button-share-data-title`) || 'Mindwendel Brainstorming',
text: this.el.getAttribute(`data-native-sharing-button-share-data-text`) || 'Join my brainstorming',
url: this.el.getAttribute(`data-native-sharing-button-share-data-url`) || document.getElementById("brainstorming-link").value
}

if (navigator.share) {
this.el.addEventListener('click', (event) => {
navigator.share(shareData)
.then() // Do nothing
.catch(err => { console.log(`Error: ${err}`) })
})
}
}
}

// see https://github.com/drag-drop-touch-js/dragdroptouch for mobile support
Hooks.Sortable = {
mounted(){
Expand Down Expand Up @@ -89,32 +65,49 @@ Hooks.Modal = {
window.addEventListener('mindwendel:hide-modal', closeModal);
}
}
Hooks.QrCodeCanvas = {

Hooks.CopyBrainstormingLinkButton = {
mounted() {
const qrCodeCanvasElement = this.el
const qrCodeUrl = qrCodeCanvasElement.getAttribute("data-qr-code-url")
new ClipboardJS(this.el);
}
}

const qrCodeOptions = buildQrCodeOptions(qrCodeUrl)
const qrCode = new QRCodeStyling(qrCodeOptions)
let refShareClickListenerFunction;
let refShareButton;

qrCode.append(qrCodeCanvasElement);
Hooks.NativeSharingButton = {
mounted() {
refShareButton = this.el;
refShareClickListenerFunction = initShareButtonClickHandler(refShareButton);
},
updated() {
refShareButton.removeEventListener("click", refShareClickListenerFunction);
refShareButton = this.el;
refShareClickListenerFunction = initShareButtonClickHandler(refShareButton);
}
}

Hooks.QrCodeDownloadButton = {
Hooks.QrCodeCanvas = {
mounted() {
const qrCodeUrl = this.el.getAttribute("data-qr-code-url");
const qrCodeFilename = this.el.getAttribute("data-qr-code-filename") || qrCodeUrl || "qrcode";
const qrCodeFileExtension = this.el.getAttribute("data-qr-code-file-extension") || "png";
appendQrCode(this.el);
},
updated() {
appendQrCode(this.el);
}
}

const qrCodeOptions = buildQrCodeOptions(qrCodeUrl)
const qrCode = new QRCodeStyling(qrCodeOptions)
let refQrClickListenerFunction;
let refQrCodeDownloadButton;

this.el && this.el.addEventListener('click', () => {
qrCode.download({ name: qrCodeFilename, extension: qrCodeFileExtension })
.then() // Do nothing
.catch(err => { console.log(`Error: ${err}`) })
})
Hooks.QrCodeDownloadButton = {
mounted() {
refQrCodeDownloadButton = this.el;
refQrClickListenerFunction = initQrDownload(refQrCodeDownloadButton);
},
updated() {
refQrCodeDownloadButton.removeEventListener("click", refQrClickListenerFunction);
refQrCodeDownloadButton = this.el;
refQrClickListenerFunction = initQrDownload(refQrCodeDownloadButton);
}
}

Expand All @@ -138,8 +131,9 @@ Hooks.SetIdeaLabelBackgroundColor = {
}
};

// The brainstorming secret from the url ("#123") is added as well to the socket. The secret is not available on the server side by default.
let liveSocket = new LiveSocket("/live", Socket, {
hooks: Hooks, params: { _csrf_token: csrfToken }
hooks: Hooks, params: { _csrf_token: csrfToken, adminSecret: window.location.hash.substring(1) }
})

// Show progress bar on live navigation and form submits
Expand Down
33 changes: 31 additions & 2 deletions assets/js/qrCodeUtils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export const buildQrCodeOptions = (qrCodeUrl) => ({
import QRCodeStyling from "qr-code-styling";

const buildQrCodeOptions = (qrCodeUrl) => ({
backgroundOptions: {
color: "#fff",
},
Expand All @@ -20,4 +22,31 @@ export const buildQrCodeOptions = (qrCodeUrl) => ({
height: 300,
type: "svg",
width: 300
})
});

export const appendQrCode = (qrCodeCanvasElement) => {
const qrCodeUrl = qrCodeCanvasElement.getAttribute("data-qr-code-url")

const qrCodeOptions = buildQrCodeOptions(qrCodeUrl)
const qrCode = new QRCodeStyling(qrCodeOptions)

qrCode.append(qrCodeCanvasElement);
}

export const initQrDownload = (button) => {
const qrCodeUrl = button.getAttribute("data-qr-code-url");
const qrCodeFilename = button.getAttribute("data-qr-code-filename") || qrCodeUrl || "qrcode";
const qrCodeFileExtension = button.getAttribute("data-qr-code-file-extension") || "png";

const qrCodeOptions = buildQrCodeOptions(qrCodeUrl)
const qrCode = new QRCodeStyling(qrCodeOptions)

const clickEventListener = () => {
qrCode.download({ name: qrCodeFilename, extension: qrCodeFileExtension })
.then() // Do nothing
.catch(err => { console.log(`Error: ${err}`) })
};

button && button.addEventListener('click', clickEventListener);
return clickEventListener;
}
18 changes: 18 additions & 0 deletions assets/js/shareUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const initShareButtonClickHandler = (button) => {
const shareData = {
title: button.getAttribute(`data-native-sharing-button-share-data-title`) || 'Mindwendel Brainstorming',
text: button.getAttribute(`data-native-sharing-button-share-data-text`) || 'Join my brainstorming',
url: document.getElementById("data-native-sharing-button-share-data-url") || document.getElementById("brainstorming-link-input-readonly").value
}

const clickHandler = (_event) => {
navigator.share(shareData)
.then() // Do nothing
.catch(err => { console.log(`Error: ${err}`) })
}

if (navigator.share) {
button.addEventListener('click', clickHandler);
return clickHandler;
}
}
36 changes: 32 additions & 4 deletions lib/mindwendel/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule Mindwendel.Accounts do
alias Mindwendel.Repo
alias Mindwendel.Accounts.User
alias Mindwendel.Brainstormings.Brainstorming
alias Mindwendel.Accounts.BrainstormingModeratingUser

require Logger

Expand Down Expand Up @@ -47,7 +48,7 @@ defmodule Mindwendel.Accounts do
end

def get_user(id) do
Repo.get(User, id) |> Repo.preload(:brainstormings)
Repo.get(User, id) |> Repo.preload([:brainstormings, :moderated_brainstormings])
rescue
Ecto.Query.CastError -> nil
end
Expand All @@ -70,6 +71,36 @@ defmodule Mindwendel.Accounts do
|> Repo.update()
end

@doc """
Adds a user as moderating user to a brainstorming.
## Examples
iex> add_moderating_user(brainstorming, user)
%Brainstorming{}
"""
def add_moderating_user(%Brainstorming{} = brainstorming, %User{} = user) do
if user.id in Enum.map(brainstorming.moderating_users, fn e -> e.id end) do
{:error}
else
%BrainstormingModeratingUser{brainstorming_id: brainstorming.id, user_id: user.id}
|> BrainstormingModeratingUser.changeset()
|> Repo.insert()
end
end

def add_moderating_user(%Brainstorming{} = brainstorming, user_id) when is_binary(user_id) do
case Ecto.UUID.dump(user_id) do
:error -> {:error}
{:ok, _} -> add_moderating_user(brainstorming, get_or_create_user(user_id))
end
end

def add_moderating_user(%Brainstorming{} = _brainstorming, user_id) when is_nil(user_id) do
{:error}
end

@doc """
Connects user to a brainstorm.
Expand All @@ -80,9 +111,6 @@ defmodule Mindwendel.Accounts do
iex> merge_brainstorming_user(brainstorming, user)
%Brainstorming{}
iex> update_user(user, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def merge_brainstorming_user(%Brainstorming{} = brainstorming, %User{} = user) do
# credo:disable-for-next-line
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Mindwendel.Brainstormings.BrainstormingModeratingUser do
defmodule Mindwendel.Accounts.BrainstormingModeratingUser do
# Not using Mindwendel.Schema as the `@derive` in there clashes here
use Ecto.Schema
alias Mindwendel.Brainstormings.Brainstorming
Expand Down
2 changes: 1 addition & 1 deletion lib/mindwendel/accounts/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Mindwendel.Accounts.User do

alias Mindwendel.Brainstormings.Brainstorming
alias Mindwendel.Brainstormings.Idea
alias Mindwendel.Brainstormings.BrainstormingModeratingUser
alias Mindwendel.Accounts.BrainstormingModeratingUser
alias Mindwendel.Accounts.BrainstormingUser

schema "users" do
Expand Down
20 changes: 13 additions & 7 deletions lib/mindwendel/brainstormings.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ defmodule Mindwendel.Brainstormings do
alias Mindwendel.Lanes
alias Mindwendel.Ideas
alias Mindwendel.Brainstormings.Brainstorming
alias Mindwendel.Brainstormings.BrainstormingModeratingUser

require Logger

Expand All @@ -36,12 +35,6 @@ defmodule Mindwendel.Brainstormings do
)
end

def add_moderating_user(%Brainstorming{} = brainstorming, %User{} = user) do
%BrainstormingModeratingUser{brainstorming_id: brainstorming.id, user_id: user.id}
|> BrainstormingModeratingUser.changeset()
|> Repo.insert()
end

@doc """
Returns the list of brainstormings.
Expand Down Expand Up @@ -237,6 +230,19 @@ defmodule Mindwendel.Brainstormings do
brainstorming
end

@doc """
Validates the given secret against the brainstorming. Returns true/false.
## Examples
iex> validate_admin_secret(brainstorming, abc)
false
"""
def validate_admin_secret(brainstorming, admin_secret_id) do
brainstorming.admin_url_id == admin_secret_id
end

@doc """
Returns a subscibe result.
Expand Down
4 changes: 1 addition & 3 deletions lib/mindwendel/brainstormings/brainstorming.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ defmodule Mindwendel.Brainstormings.Brainstorming do
alias Mindwendel.Brainstormings.Idea
alias Mindwendel.Brainstormings.IdeaLabel
alias Mindwendel.Brainstormings.Lane
alias Mindwendel.Brainstormings.BrainstormingModeratingUser
alias Mindwendel.Accounts.BrainstormingModeratingUser
alias Mindwendel.Accounts.User
alias Mindwendel.Accounts.BrainstormingUser

schema "brainstormings" do
field :name, :string
field :option_show_link_to_settings, :boolean
field :option_allow_manual_ordering, :boolean
# credo:disable-for-next-line
# Todo: The following line can be changed `field :admin_url_id, Ecto.UUID, autogenerate: true`
Expand All @@ -35,7 +34,6 @@ defmodule Mindwendel.Brainstormings.Brainstorming do
brainstorming
|> cast(attrs, [
:name,
:option_show_link_to_settings,
:option_allow_manual_ordering,
:filter_labels_ids
])
Expand Down
6 changes: 0 additions & 6 deletions lib/mindwendel/brainstormings/idea.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,19 @@ defmodule Mindwendel.Brainstormings.Idea do
alias Mindwendel.UrlPreview
alias Mindwendel.Accounts.User

@label_values [:label_1, :label_2, :label_3, :label_4, :label_5]
@max_file_attachments 2

schema "ideas" do
field :body, :string
field :position_order, :integer
field :username, :string, default: "Anonymous"
field :comments_count, :integer
field :deprecated_label, Ecto.Enum, source: :label, values: @label_values
has_one :link, Link
belongs_to :user, User
has_many :likes, Like
has_many :comments, Comment, preload_order: [desc: :inserted_at]
has_many :files, File
belongs_to :brainstorming, Brainstorming
belongs_to :label, IdeaLabel, on_replace: :nilify
belongs_to :lane, Lane
many_to_many :idea_labels, IdeaLabel, join_through: IdeaIdeaLabel, on_replace: :delete

Expand All @@ -45,16 +42,13 @@ defmodule Mindwendel.Brainstormings.Idea do
:body,
:brainstorming_id,
:lane_id,
:deprecated_label,
:label_id,
:user_id,
:position_order,
:comments_count
])
|> validate_required([:username, :body, :brainstorming_id])
|> maybe_put_idea_labels(attrs)
|> validate_length(:body, min: 1, max: 1023)
|> validate_inclusion(:deprecated_label, @label_values)
|> add_position_order_if_missing()
|> validate_attachment_count(attrs)
|> maybe_put_attachments(idea, attrs)
Expand Down
1 change: 0 additions & 1 deletion lib/mindwendel/ideas.ex
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ defmodule Mindwendel.Ideas do
|> Repo.preload([
:link,
:likes,
:label,
:idea_labels,
:comments
])
Expand Down
Loading

0 comments on commit daedcc9

Please sign in to comment.