From e4080772b511e8dd436fddc79de10f44e4d83ff6 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 27 Oct 2017 23:54:20 +0900 Subject: Use contenthash for ExtractTextWebpackPlugin (#5462) [hash] is not documented. --- config/webpack/shared.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config') diff --git a/config/webpack/shared.js b/config/webpack/shared.js index cd642a28a..5ff267fc5 100644 --- a/config/webpack/shared.js +++ b/config/webpack/shared.js @@ -55,7 +55,7 @@ module.exports = { resource.request = resource.request.replace(/^history/, 'history/es'); } ), - new ExtractTextPlugin(env.NODE_ENV === 'production' ? '[name]-[hash].css' : '[name].css'), + new ExtractTextPlugin(env.NODE_ENV === 'production' ? '[name]-[contenthash].css' : '[name].css'), new ManifestPlugin({ publicPath: output.publicPath, writeToFileEmit: true, -- cgit From 2cbb8e8cd14359dbf60180f0bdc56630148e29f4 Mon Sep 17 00:00:00 2001 From: Marcin Mikołajczak Date: Sat, 28 Oct 2017 05:43:20 +0200 Subject: i18n: Update Polish translation (#5547) --- config/locales/pl.yml | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'config') diff --git a/config/locales/pl.yml b/config/locales/pl.yml index c58c1c2f8..0d979225d 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -130,11 +130,15 @@ pl: enable: Włącz enabled_msg: Pomyślnie przywrócono emoji image_hint: Plik PNG ważący do 50KB + listed: Widoczne new: title: Dodaj nowe niestandardowe emoji shortcode: Shortcode shortcode_hint: Co najmniej 2 znaki, tylko znaki alfanumeryczne i podkreślniki title: Niestandardowe emoji + unlisted: Niewidoczne + update_failed_msg: Nie udało się zaktualizować emoji + updated_msg: Pomyślnie zaktualizowano emoji upload: Wyślij domain_blocks: add_new: Dodaj nową -- cgit From 4080569c2dd6d9d8b794cecd4f11492a2f57fcea Mon Sep 17 00:00:00 2001 From: Alda Marteau-Hardi Date: Sat, 28 Oct 2017 19:08:37 +0200 Subject: Fix a grammatical error in the notifications. (#5555) --- config/locales/fr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config') diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 0d9c227f3..55588d111 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -437,7 +437,7 @@ fr: action_favourite: Ajouter aux favoris title: "%{name} vous a mentionné·e" reblog: - title: "%{name} a partagé⋅e votre statut" + title: "%{name} a partagé votre statut" remote_follow: acct: Entrez votre pseudo@instance depuis lequel vous voulez suivre ce⋅tte utilisateur⋅rice missing_resource: L’URL de redirection n’a pas pu être trouvée -- cgit From 29609fbb6a2bdfb8937077fac9f1aa280f730633 Mon Sep 17 00:00:00 2001 From: SerCom_KC Date: Mon, 30 Oct 2017 11:34:58 +0800 Subject: Updating Chinese (Simplified) translations (#5508) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * i18n: (zh-CN) fix punctuations and spaces Spaces are fixed according to https://github.com/sparanoid/chinese-copywriting-guidelines * i18n: (zh-CN) fix punctuation * i18n: (zh-CN) Adapt official translation of Discourse Privacy Policy from GitHub, with minor fixes https://github.com/discourse/discourse/blob/master/config/locales/server.zh_CN.yml#L2677 * i18n: (zh-CN) Update missing translations * i18n: (zh-CN) Fixing errors * i18n: (zh-CN) Fix indent error * i18n: (zh-CN) Fix language tag * i18n: (zh-CN) Remove quotes * i18n: (zh-CN) Update translation (#5485) * i18n: (zh-CN) Remove whitespaces, x -> × * i18n: (zh-CN) Rewording on time distance * i18n: (zh-CN) Overall improvements * i18n: (zh-CN) i18n-tasks normalization * i18n: (zh-CN) Add missing translation --- app/javascript/mastodon/locales/zh-CN.json | 208 ++++---- .../confirmation_instructions.zh-cn.html.erb | 13 +- .../confirmation_instructions.zh-cn.text.erb | 12 +- .../user_mailer/password_change.zh-cn.html.erb | 4 +- .../user_mailer/password_change.zh-cn.text.erb | 4 +- .../reset_password_instructions.zh-cn.html.erb | 9 +- .../reset_password_instructions.zh-cn.text.erb | 9 +- config/locales/activerecord.zh-CN.yml | 13 + config/locales/simple_form.zh-CN.yml | 59 ++- config/locales/zh-CN.yml | 560 ++++++++++++++++----- 10 files changed, 602 insertions(+), 289 deletions(-) create mode 100644 config/locales/activerecord.zh-CN.yml (limited to 'config') diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 827c815cf..f0f23959a 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -1,25 +1,25 @@ { "account.block": "屏蔽 @{name}", "account.block_domain": "隐藏一切来自 {domain} 的嘟文", - "account.disclaimer_full": "下列资料不一定完整。", + "account.disclaimer_full": "此处显示的信息可能不是全部内容。", "account.edit_profile": "修改个人资料", "account.follow": "关注", "account.followers": "关注者", - "account.follows": "正关注", - "account.follows_you": "关注你", + "account.follows": "正在关注", + "account.follows_you": "关注了你", "account.media": "媒体", "account.mention": "提及 @{name}", - "account.mute": "将 @{name} 静音", + "account.mute": "静音 @{name}", "account.posts": "嘟文", "account.report": "举报 @{name}", - "account.requested": "等待审批", - "account.share": "分享 @{name}的个人资料", - "account.unblock": "解除对 @{name} 的屏蔽", + "account.requested": "正在等待对方同意。点击以取消发送关注请求", + "account.share": "分享 @{name} 的个人资料", + "account.unblock": "不再屏蔽 @{name}", "account.unblock_domain": "不再隐藏 {domain}", "account.unfollow": "取消关注", - "account.unmute": "取消 @{name} 的静音", + "account.unmute": "不再静音 @{name}", "account.view_full_profile": "查看完整资料", - "boost_modal.combo": "如你想在下次路过时显示,请按{combo},", + "boost_modal.combo": "下次按住 {combo} 即可跳过此提示", "bundle_column_error.body": "载入组件出错。", "bundle_column_error.retry": "重试", "bundle_column_error.title": "网络错误", @@ -37,72 +37,72 @@ "column.public": "跨站公共时间轴", "column_back_button.label": "返回", "column_header.hide_settings": "隐藏设置", - "column_header.moveLeft_settings": "将栏左移", - "column_header.moveRight_settings": "将栏右移", + "column_header.moveLeft_settings": "将此栏左移", + "column_header.moveRight_settings": "将此栏右移", "column_header.pin": "固定", "column_header.show_settings": "显示设置", - "column_header.unpin": "取下", + "column_header.unpin": "取消固定", "column_subheading.navigation": "导航", "column_subheading.settings": "设置", - "compose_form.lock_disclaimer": "你的帐户没 {locked}. 任何人可以通过关注你来查看只有关注者可见的嘟文.", + "compose_form.lock_disclaimer": "你的帐户没有{locked}。任何人都可以通过关注你来查看仅关注者可见的嘟文。", "compose_form.lock_disclaimer.lock": "被保护", "compose_form.placeholder": "在想啥?", "compose_form.publish": "嘟嘟", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive": "将媒体文件标示为“敏感内容”", - "compose_form.spoiler": "将部分文本藏于警告消息之后", - "compose_form.spoiler_placeholder": "敏感内容的警告消息", + "compose_form.sensitive": "将媒体文件标记为“敏感内容”", + "compose_form.spoiler": "将部分文字隐藏于警告消息之后", + "compose_form.spoiler_placeholder": "隐藏文字的警告消息", "confirmation_modal.cancel": "取消", "confirmations.block.confirm": "屏蔽", - "confirmations.block.message": "想好了,真的要屏蔽 {name}?", + "confirmations.block.message": "想好了,真的要屏蔽 {name}?", "confirmations.delete.confirm": "删除", - "confirmations.delete.message": "想好了,真的要删除这条嘟文?", + "confirmations.delete.message": "想好了,真的要删除这条嘟文?", "confirmations.domain_block.confirm": "隐藏整个网站", - "confirmations.domain_block.message": "你真的真的确定要隐藏整个 {domain} ?多数情况下,封锁或静音几个特定目标就好。", + "confirmations.domain_block.message": "你真的真的确定要隐藏整个 {domain}?多数情况下,屏蔽或静音几个特定的用户就应该能满足你的需要了。", "confirmations.mute.confirm": "静音", - "confirmations.mute.message": "想好了,真的要静音 {name}?", + "confirmations.mute.message": "想好了,真的要静音 {name}?", "confirmations.unfollow.confirm": "取消关注", - "confirmations.unfollow.message": "确定要取消关注 {name}吗?", - "embed.instructions": "要内嵌此嘟文,请将以下代码贴进你的网站。", - "embed.preview": "到时大概长这样:", + "confirmations.unfollow.message": "确定要取消关注 {name} 吗?", + "embed.instructions": "要在你的网站上嵌入这条嘟文,请复制以下代码。", + "embed.preview": "它会像这样显示出来:", "emoji_button.activity": "活动", - "emoji_button.custom": "Custom", + "emoji_button.custom": "自定义", "emoji_button.flags": "旗帜", "emoji_button.food": "食物和饮料", "emoji_button.label": "加入表情符号", "emoji_button.nature": "自然", - "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "木有这个表情符号!(╯°□°)╯︵ ┻━┻", "emoji_button.objects": "物体", "emoji_button.people": "人物", - "emoji_button.recent": "Frequently used", + "emoji_button.recent": "常用", "emoji_button.search": "搜索…", - "emoji_button.search_results": "Search results", + "emoji_button.search_results": "搜索结果", "emoji_button.symbols": "符号", - "emoji_button.travel": "旅途和地点", - "empty_column.community": "本站时间轴暂时未有内容,快嘟几个来抢头香啊!", - "empty_column.hashtag": "这个标签暂时未有内容。", + "emoji_button.travel": "旅行和地点", + "empty_column.community": "本站时间轴暂时没有内容,快嘟几个来抢头香啊!", + "empty_column.hashtag": "这个话题标签下暂时没有内容。", "empty_column.home": "你还没有关注任何用户。快看看{public},向其他用户搭讪吧。", "empty_column.home.public_timeline": "公共时间轴", - "empty_column.notifications": "你没有任何通知纪录,快向其他用户搭讪吧。", - "empty_column.public": "跨站公共时间轴暂时没有内容!快写一些公共的嘟文,或者关注另一些服务器实例的用户吧!你和本站、友站的交流,将决定这里出现的内容。", - "follow_request.authorize": "批准", + "empty_column.notifications": "你还没有收到过通知信息,快向其他用户搭讪吧。", + "empty_column.public": "这里神马都没有!写一些公开的嘟文,或者关注其他实例的用户,这里就会有嘟文出现了哦!", + "follow_request.authorize": "同意", "follow_request.reject": "拒绝", - "getting_started.appsshort": "Apps", - "getting_started.faq": "FAQ", + "getting_started.appsshort": "应用", + "getting_started.faq": "常见问题", "getting_started.heading": "开始使用", - "getting_started.open_source_notice": "Mastodon 是一个开放源码的软件。你可以在官方 GitHub ({github}) 贡献或者回报问题。", + "getting_started.open_source_notice": "Mastodon 是一个开放源码的软件。你可以在官方 GitHub({github})贡献或者回报问题。", "getting_started.userguide": "用户指南", - "home.column_settings.advanced": "高端", - "home.column_settings.basic": "基本", - "home.column_settings.filter_regex": "使用正则表达式 (regex) 过滤", - "home.column_settings.show_reblogs": "显示被转的嘟文", - "home.column_settings.show_replies": "显示回应嘟文", - "home.settings": "字段设置", + "home.column_settings.advanced": "高级设置", + "home.column_settings.basic": "基本设置", + "home.column_settings.filter_regex": "使用正则表达式(regex)过滤", + "home.column_settings.show_reblogs": "显示转嘟", + "home.column_settings.show_replies": "显示回复", + "home.settings": "栏目设置", "lightbox.close": "关闭", "lightbox.next": "下一步", "lightbox.previous": "上一步", "loading_indicator.label": "加载中……", - "media_gallery.toggle_visible": "打开或关上", + "media_gallery.toggle_visible": "切换显示/隐藏", "missing_indicator.label": "找不到内容", "navigation_bar.blocks": "被屏蔽的用户", "navigation_bar.community_timeline": "本站时间轴", @@ -119,9 +119,9 @@ "notification.follow": "{name} 开始关注你", "notification.mention": "{name} 提及你", "notification.reblog": "{name} 转嘟了你的嘟文", - "notifications.clear": "清空通知纪录", - "notifications.clear_confirmation": "你确定要清空通知纪录吗?", - "notifications.column_settings.alert": "显示桌面通知", + "notifications.clear": "清空通知列表", + "notifications.clear_confirmation": "你确定要清空通知列表吗?", + "notifications.column_settings.alert": "桌面通知", "notifications.column_settings.favourite": "你的嘟文被收藏:", "notifications.column_settings.follow": "关注你:", "notifications.column_settings.mention": "提及你:", @@ -132,90 +132,90 @@ "notifications.column_settings.sound": "播放音效", "onboarding.done": "出发!", "onboarding.next": "下一步", - "onboarding.page_five.public_timelines": "本站时间轴显示来自 {domain} 的所有人的公共嘟文。 跨站公共时间轴显示 {domain} 上的各位关注的来自所有Mastodon服务器实例上的人发表的公共嘟文。这些就是寻人好去处的公共时间轴啦。", - "onboarding.page_four.home": "你的主时间轴上是你关注的用户的嘟文.", - "onboarding.page_four.notifications": "如果你和他人产生了互动,便会出现在通知列上啦~", - "onboarding.page_one.federation": "Mastodon是由一系列独立的服务器共同打造的强大的社交网络,我们将这些独立但又相互连接的服务器叫做服务器实例。", - "onboarding.page_one.handle": "你在 {domain}, {handle} 就是你的完整帐户名称。", - "onboarding.page_one.welcome": "欢迎来到 Mastodon!", + "onboarding.page_five.public_timelines": "本站时间轴显示的是由本站({domain})用户发布的所有公开嘟文。跨站公共时间轴显示的的是由本站用户关注对象所发布的所有公开嘟文。这些就是寻人好去处的公共时间轴啦。", + "onboarding.page_four.home": "你的主页上的时间轴上显示的是你关注对象的嘟文。", + "onboarding.page_four.notifications": "如果有人与你互动,便会出现在通知栏中哦~", + "onboarding.page_one.federation": "Mastodon 是由一系列独立的服务器共同打造的强大的社交网络,我们将这些各自独立但又相互连接的服务器叫做实例。", + "onboarding.page_one.handle": "你在 {domain},{handle} 就是你的完整帐户名称。", + "onboarding.page_one.welcome": "欢迎来到 Mastodon!", "onboarding.page_six.admin": "{admin} 是你所在服务器实例的管理员.", - "onboarding.page_six.almost_done": "差不多了…", - "onboarding.page_six.appetoot": "嗷呜~", - "onboarding.page_six.apps_available": "也有适用于 iOS, Android 和其它平台的 {apps} 咯~", - "onboarding.page_six.github": "Mastodon 是自由的开放源代码软件。欢迎来 {github} 报告问题,提交功能请求,或者贡献代码 :-)", + "onboarding.page_six.almost_done": "差不多了……", + "onboarding.page_six.appetoot": "嗷呜~", + "onboarding.page_six.apps_available": "我们还有适用于 iOS、Android 和其它平台的{apps}哦~", + "onboarding.page_six.github": "Mastodon 是自由的开源软件。欢迎前往 {github} 反馈问题、提出对新功能的建议或贡献代码 :-)", "onboarding.page_six.guidelines": "社区指南", - "onboarding.page_six.read_guidelines": "别忘了看看 {domain} 的 {guidelines}!", - "onboarding.page_six.various_app": "移动应用程序", - "onboarding.page_three.profile": "修改你的个人资料,比如头像、简介、和昵称等等。在那还可以找到其它首选项。", - "onboarding.page_three.search": "用搜索来找人和标签吧,比如 {illustration} 或者 {introductions}。想找其它服务器实例上的人,用完整帐户名称(用户名@域名)啦。", - "onboarding.page_two.compose": "从这里开始嘟!上面的按钮提供了上传图片,修改隐私设置和提示敏感内容等多种功能。.", - "onboarding.skip": "好啦好啦我知道啦", - "privacy.change": "调整隐私设置", - "privacy.direct.long": "只有提及的用户能看到", - "privacy.direct.short": "私人消息", - "privacy.private.long": "只有关注你用户能看到", - "privacy.private.short": "关注者", - "privacy.public.long": "在公共时间轴显示", - "privacy.public.short": "公共", - "privacy.unlisted.long": "公开,但不在公共时间轴显示", - "privacy.unlisted.short": "公开", - "relative_time.days": "{number}d", - "relative_time.hours": "{number}h", - "relative_time.just_now": "now", - "relative_time.minutes": "{number}m", - "relative_time.seconds": "{number}s", + "onboarding.page_six.read_guidelines": "别忘了看看 {domain} 的{guidelines}!", + "onboarding.page_six.various_app": "移动设备应用", + "onboarding.page_three.profile": "你可以修改你的个人资料,比如头像、简介和昵称等偏好设置。", + "onboarding.page_three.search": "你可以通过搜索功能寻找用户和话题标签,比如{illustration}或者{introductions}。如果你想搜索其他实例上的用户,就需要输入完整帐户名称(用户名@域名)哦。", + "onboarding.page_two.compose": "在撰写栏中开始嘟嘟吧!下方的按钮分别用来上传图片,修改嘟文可见范围,以及添加警告信息。", + "onboarding.skip": "跳过", + "privacy.change": "设置嘟文可见范围", + "privacy.direct.long": "只有被提及的用户能看到", + "privacy.direct.short": "私信", + "privacy.private.long": "只有关注你的用户能看到", + "privacy.private.short": "仅关注者", + "privacy.public.long": "所有人可见,并会出现在公共时间轴上", + "privacy.public.short": "公开", + "privacy.unlisted.long": "所有人可见,但不会出现在公共时间轴上", + "privacy.unlisted.short": "不公开", + "relative_time.days": "{number} 天", + "relative_time.hours": "{number} 时", + "relative_time.just_now": "刚刚", + "relative_time.minutes": "{number} 分", + "relative_time.seconds": "{number} 秒", "reply_indicator.cancel": "取消", - "report.placeholder": "额外消息", + "report.placeholder": "附言", "report.submit": "提交", - "report.target": "Reporting", + "report.target": "举报 {target}", "search.placeholder": "搜索", - "search_popout.search_format": "Advanced search format", - "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", - "search_popout.tips.user": "user", - "search_results.total": "{count, number} {count, plural, one {result} other {results}}", + "search_popout.search_format": "高级搜索格式", + "search_popout.tips.hashtag": "话题标签", + "search_popout.tips.status": "嘟文", + "search_popout.tips.text": "使用普通字符进行搜索将会返回昵称、用户名和话题标签", + "search_popout.tips.user": "用户", + "search_results.total": "共 {count, number} 个结果", "standalone.public_title": "大家都在干啥?", - "status.cannot_reblog": "没法转嘟这条嘟文啦……", + "status.cannot_reblog": "无法转嘟这条嘟文", "status.delete": "删除", "status.embed": "嵌入", "status.favourite": "收藏", "status.load_more": "加载更多", "status.media_hidden": "隐藏媒体内容", "status.mention": "提及 @{name}", - "status.more": "More", - "status.mute_conversation": "静音对话", + "status.more": "更多", + "status.mute_conversation": "静音此对话", "status.open": "展开嘟文", - "status.pin": "置顶到资料", + "status.pin": "在个人资料页面置顶", "status.reblog": "转嘟", - "status.reblogged_by": "{name} 转嘟", - "status.reply": "回应", - "status.replyAll": "回应整串", + "status.reblogged_by": "{name} 转嘟了", + "status.reply": "回复", + "status.replyAll": "回复所有人", "status.report": "举报 @{name}", "status.sensitive_toggle": "点击显示", "status.sensitive_warning": "敏感内容", - "status.share": "Share", - "status.show_less": "减少显示", - "status.show_more": "显示更多", - "status.unmute_conversation": "解禁对话", - "status.unpin": "解除置顶", + "status.share": "分享", + "status.show_less": "隐藏内容", + "status.show_more": "显示内容", + "status.unmute_conversation": "不再静音此对话", + "status.unpin": "在个人资料页面取消置顶", "tabs_bar.compose": "撰写", "tabs_bar.federated_timeline": "跨站", "tabs_bar.home": "主页", "tabs_bar.local_timeline": "本站", "tabs_bar.notifications": "通知", - "upload_area.title": "将文件拖放至此上传", + "upload_area.title": "将文件拖放到此处开始上传", "upload_button.label": "上传媒体文件", - "upload_form.description": "Describe for the visually impaired", - "upload_form.undo": "还原", - "upload_progress.label": "上传中……", - "video.close": "关闭影片", + "upload_form.description": "为视觉障碍人士添加文字说明", + "upload_form.undo": "取消上传", + "upload_progress.label": "上传中…", + "video.close": "关闭视频", "video.exit_fullscreen": "退出全屏", - "video.expand": "展开影片", + "video.expand": "展开视频", "video.fullscreen": "全屏", - "video.hide": "隐藏影片", + "video.hide": "隐藏视频", "video.mute": "静音", "video.pause": "暂停", "video.play": "播放", - "video.unmute": "解除静音" + "video.unmute": "取消静音" } diff --git a/app/views/user_mailer/confirmation_instructions.zh-cn.html.erb b/app/views/user_mailer/confirmation_instructions.zh-cn.html.erb index de2f8b6e0..8a676498a 100644 --- a/app/views/user_mailer/confirmation_instructions.zh-cn.html.erb +++ b/app/views/user_mailer/confirmation_instructions.zh-cn.html.erb @@ -1,10 +1,13 @@ -

<%= @resource.email %> ,嗨呀!

+

<%= @resource.email %>,你好呀!

-

你刚刚在 <%= @instance %> 创建了帐号。

+

你刚刚在 <%= @instance %> 创建了一个帐户呢。

-

点击下面的链接来完成注册啦 :
+

点击下面的链接来完成注册啦:
<%= link_to '确认帐户', confirmation_url(@resource, confirmation_token: @token) %> -

别忘了看看 <%= link_to '使用条款', terms_url %>。

+

上面的链接按不动?把下面的链接复制到地址栏再试试:
+<%= confirmation_url(@resource, confirmation_token: @token) %> -

<%= @instance %> 敬上

\ No newline at end of file +

记得读一读我们的<%= link_to '使用条款', terms_url %>哦。

+ +

来自 <%= @instance %> 管理团队

diff --git a/app/views/user_mailer/confirmation_instructions.zh-cn.text.erb b/app/views/user_mailer/confirmation_instructions.zh-cn.text.erb index d7d4b4b23..25d901f16 100644 --- a/app/views/user_mailer/confirmation_instructions.zh-cn.text.erb +++ b/app/views/user_mailer/confirmation_instructions.zh-cn.text.erb @@ -1,10 +1,10 @@ -<%= @resource.email %> ,嗨呀! +<%= @resource.email %>,你好呀! -你刚刚在 <%= @instance %> 创建了帐号。 +你刚刚在 <%= @instance %> 创建了一个帐户呢。 -点击下面的链接来完成注册啦 :
-<%= link_to '确认帐户', confirmation_url(@resource, confirmation_token: @token) %> +点击下面的链接来完成注册啦: +<%= confirmation_url(@resource, confirmation_token: @token) %> -别忘了看看 <%= link_to 'terms and conditions', terms_url %>。 +记得读一读我们的使用条款哦:<%= terms_url %> -<%= @instance %> 敬上 \ No newline at end of file +来自 <%= @instance %> 管理团队 \ No newline at end of file diff --git a/app/views/user_mailer/password_change.zh-cn.html.erb b/app/views/user_mailer/password_change.zh-cn.html.erb index 115030af4..64e8b6b2f 100644 --- a/app/views/user_mailer/password_change.zh-cn.html.erb +++ b/app/views/user_mailer/password_change.zh-cn.html.erb @@ -1,3 +1,3 @@ -

<%= @resource.email %>,嗨呀!

+

<%= @resource.email %>,你好呀!

-

这只是一封用来通知你的密码已经被修改的邮件。_(:3」∠)_

+

提醒一下,你在 <%= @instance %> 上的密码被更改了哦。

diff --git a/app/views/user_mailer/password_change.zh-cn.text.erb b/app/views/user_mailer/password_change.zh-cn.text.erb index 5a989d324..dbc065173 100644 --- a/app/views/user_mailer/password_change.zh-cn.text.erb +++ b/app/views/user_mailer/password_change.zh-cn.text.erb @@ -1,3 +1,3 @@ -<%= @resource.email %>,嗨呀! +<%= @resource.email %>,你好呀! -这只是一封用来通知你的密码已经被修改的邮件。_(:3」∠)_ +提醒一下,你在 <%= @instance %> 上的密码被更改了哦。 diff --git a/app/views/user_mailer/reset_password_instructions.zh-cn.html.erb b/app/views/user_mailer/reset_password_instructions.zh-cn.html.erb index 51e3073f1..124305675 100644 --- a/app/views/user_mailer/reset_password_instructions.zh-cn.html.erb +++ b/app/views/user_mailer/reset_password_instructions.zh-cn.html.erb @@ -1,7 +1,8 @@ -

<%= @resource.email %> ,嗨呀!!

+

<%= @resource.email %>,你好呀!

-

有人(但愿是你)请求更改你Mastodon帐户的密码。如果是你的话,请点击下面的链接:

+

有人想修改你在 <%= @instance %> 上的密码呢。如果你确实想修改密码的话,点击下面的链接吧:

-

<%= link_to '更改密码', edit_password_url(@resource, reset_password_token: @token) %>

+

<%= link_to '修改密码', edit_password_url(@resource, reset_password_token: @token) %>

-

如果不是的话,忘了它吧。只有你本人通过上面的链接设置新的密码以后你的新密码才会生效。

+

如果你不想修改密码的话,还请忽略这封邮件哦。

+

在你点击上面的链接并修改密码前,你的密码是不会改变的。

diff --git a/app/views/user_mailer/reset_password_instructions.zh-cn.text.erb b/app/views/user_mailer/reset_password_instructions.zh-cn.text.erb index 7df590f78..f7cd88847 100644 --- a/app/views/user_mailer/reset_password_instructions.zh-cn.text.erb +++ b/app/views/user_mailer/reset_password_instructions.zh-cn.text.erb @@ -1,7 +1,8 @@ -<%= @resource.email %> ,嗨呀!! +<%= @resource.email %>,你好呀! -有人(但愿是你)请求更改你Mastodon帐户的密码。如果是你的话,请点击下面的链接: +有人想修改你在 <%= @instance %> 上的密码呢。如果你确实想修改密码的话,点击下面的链接吧: -<%= link_to '更改密码', edit_password_url(@resource, reset_password_token: @token) %> +<%= edit_password_url(@resource, reset_password_token: @token) %> -如果不是的话,忘了它吧。只有你本人通过上面的链接设置新的密码以后你的新密码才会生效。 +如果你不想修改密码的话,还请忽略这封邮件哦。 +在你点击上面的链接并修改密码前,你的密码是不会改变的。 diff --git a/config/locales/activerecord.zh-CN.yml b/config/locales/activerecord.zh-CN.yml new file mode 100644 index 000000000..8628d6677 --- /dev/null +++ b/config/locales/activerecord.zh-CN.yml @@ -0,0 +1,13 @@ +--- +zh-CN: + activerecord: + errors: + models: + account: + attributes: + username: + invalid: 只能使用字母、数字和下划线 + status: + attributes: + reblog: + taken: 已经被转嘟过 diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml index eafaa972e..8bd3b576c 100644 --- a/config/locales/simple_form.zh-CN.yml +++ b/config/locales/simple_form.zh-CN.yml @@ -3,49 +3,60 @@ zh-CN: simple_form: hints: defaults: - avatar: 最大 2MB,限 PNG, GIF 或 JPG 格式,将缩到 120x120px - display_name: 不起过 30 个字符 - header: 最大 2MB,限 PNG, GIF 或 JPG 格式,将缩到 700x335px - locked: 默认仅向粉丝公开嘟文,需要手工批准粉丝关注请求。 - note: 最多 160 个字符 + avatar: 文件大小限制 2MB,只支持 PNG、GIF 或 JPG 格式。图片分辨率将会压缩至 120×120px + digest: 在你长时间未登录的情况下,我们会向你发送一份含有提及你的嘟文的摘要邮件 + display_name: 还能输入 %{count} 个字符 + header: 文件大小限制 2MB,只支持 PNG、GIF 或 JPG 格式。图片分辨率将会压缩至 700×335px + locked: 你需要手动审核所有关注请求 + note: 还能输入 %{count} 个字符 + setting_noindex: 此设置会影响到你的公开个人资料以及嘟文页面 + setting_theme: 此设置会影响到你从任意设备登录时 Mastodon 的显示样式 imports: - data: 从其他服务器节点导出的 CSV 文件 + data: 请上传从其他 Mastodon 实例导出的 CSV 文件 sessions: - otp: 输入你手机生成的两步验证码,或者恢复代码。 + otp: 输入你手机上生成的两步验证码,或者任意一个恢复代码。 user: - filtered_languages: 下列被选择的语言的嘟文将不会出现在你的公共时间轴上。 + filtered_languages: 勾选语言的嘟文将不会出现在你的公共时间轴上 labels: defaults: avatar: 头像 confirm_new_password: 确认新密码 confirm_password: 确认密码 current_password: 当前密码 - data: 数据 - display_name: 显示名 - email: 邮箱 - filtered_languages: 屏蔽下列语言的嘟文 - header: 个人页面顶部 + data: 数据文件 + display_name: 昵称 + email: 电子邮件地址 + filtered_languages: 语言过滤 + header: 个人资料页横幅图片 locale: 语言 - locked: 隐私模式(锁嘟) + locked: 保护你的帐户(锁嘟) new_password: 新密码 note: 简介 - otp_attempt: 两步认证码 + otp_attempt: 两步认证代码 password: 密码 + setting_auto_play_gif: 自动播放 GIF 动画 setting_boost_modal: 在转嘟前询问我 - setting_default_privacy: 嘟文默认隐私度 - severity: 等级 + setting_default_privacy: 嘟文默认可见范围 + setting_default_sensitive: 总是将我发送的媒体文件标记为敏感内容 + setting_delete_modal: 在删除嘟文前询问我 + setting_noindex: 禁止搜索引擎建立索引 + setting_reduce_motion: 降低过渡动画效果 + setting_system_font_ui: 使用系统默认字体 + setting_theme: 站点主题 + setting_unfollow_modal: 在取消关注前询问我 + severity: 级别 type: 导入数据类型 username: 用户名 interactions: - must_be_follower: 隐藏没有关注你的用户的通知 - must_be_following: 隐藏你不关注的用户的通知 + must_be_follower: 屏蔽来自未关注你的用户的通知 + must_be_following: 屏蔽来自你未关注的用户的通知 notification_emails: digest: 发送摘要邮件 - favourite: 当有用户赞了你的嘟文时,发电邮通知 - follow: 当有用户关注你时,发电邮通知 - follow_request: 当有用户要求关注你时,发电邮通知 - mention: 当有用户在嘟文中提及你时,发电邮通知 - reblog: 当有用户转嘟了你的嘟文时,发电邮通知 + favourite: 当有用户收藏了你的嘟文时,发送电子邮件提醒我 + follow: 当有用户关注你时,发送电子邮件提醒我 + follow_request: 当有用户向你发送关注请求时,发送电子邮件提醒我 + mention: 当有用户在嘟文中提及你时,发送电子邮件提醒我 + reblog: 当有用户转嘟了你的嘟文时,发送电子邮件提醒我 'no': 否 required: mark: "*" diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 44d0f3803..4a71a9959 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -1,196 +1,335 @@ --- zh-CN: about: - about_mastodon_html: Mastodon(长毛象)是一个自由、开放源码的社交网站。它是一个分布式的服务,避免你的通信被单一商业机构垄断操控。请你选择一家你信任的 Mastodon 实例,在上面创建帐号,然后你就可以和任一 Mastodon 实例上的用户互通,享受无缝的社交交流。 + about_hashtag_html: 这里展示的是带有话题标签 #%{hashtag} 的公开嘟文。如果你在象毛世界中拥有一个帐户,就可以加入讨论。 + about_mastodon_html: Mastodon(长毛象)是一个基于开放式网络协议和自由、开源软件建立的社交网络,有着类似于电子邮件的分布式设计。 about_this: 关于本实例 - closed_registrations: 这个实例目前不开放注册 _(:3」∠)_ + closed_registrations: 这个实例目前没有开放注册。不过,你可以前往其他实例注册一个帐户,同样可以加入到这个网络中哦! contact: 联络 + contact_missing: 未设定 + contact_unavailable: 未公开 description_headline: 关于 %{domain} domain_count_after: 个其它实例 domain_count_before: 现已接入 - other_instances: 其它实例 + extended_description_html: | +

这里可以写一些规定

+

本站尚未设置详细介绍。

+ features: + humane_approach_body: Mastodon 从其他网络的失败经验中汲取了教训,致力于在与错误的社交媒体使用方式的斗争中做出符合伦理化设计的选择。 + humane_approach_title: 更加以人为本 + not_a_product_body: Mastodon 绝非一个商业网络。这里既没有广告,也没有数据挖掘,更没有围墙花园。中心机构在这里不复存在。 + not_a_product_title: 作为用户,你并非一件商品 + real_conversation_body: Mastodon 有着高达 500 字的字数限制,以及对内容的细化控制和媒体警告提示的支持,只为让你能够畅所欲言。 + real_conversation_title: 为真正的交流而生 + within_reach_body: 通过一个面向开发者友好的 API 生态系统,Mastodon 让你可以随时随地通过众多 iOS、Android 以及其他平台的应用与朋友们保持联系。 + within_reach_title: 始终触手可及 + find_another_instance: 寻找另一个实例 + generic_description: "%{domain} 是这个庞大网络中的一台服务器" + hosted_on: 一个在 %{domain} 上运行的 Mastodon 实例 + learn_more: 详细了解 + other_instances: 其他实例 source_code: 源码 status_count_after: 条嘟文 status_count_before: 他们共嘟出了 user_count_after: 位用户 user_count_before: 这里共注册有 + what_is_mastodon: Mastodon 是什么? accounts: follow: 关注 - followers: 粉丝 - following: 关注 - nothing_here: 神马都没有! + followers: 关注者 + following: 正在关注 + media: 媒体 + nothing_here: 这里神马都没有! people_followed_by: 正关注 people_who_follow: 粉丝 posts: 嘟文 + posts_with_replies: 嘟文和回复 remote_follow: 跨站关注 + reserved_username: 此用户名已保留 + roles: + admin: 管理员 unfollow: 取消关注 admin: + account_moderation_notes: + account: 管理员 + create: 新建 + created_at: 日期 + created_msg: 管理记录建立成功! + delete: 删除 + destroyed_msg: 管理记录删除成功! accounts: are_you_sure: 你确定吗? confirm: 确认 confirmed: 已确认 - disable_two_factor_authentication: 两步认证无效 - display_name: 显示名称 + disable_two_factor_authentication: 停用两步认证 + display_name: 昵称 domain: 域名 edit: 编辑 - email: 电邮地址 + email: 电子邮件地址 feed_url: 订阅 URL followers: 关注者 + followers_url: 关注者(Followers)URL follows: 正在关注 - ip: IP地址 + inbox_url: 收件箱(Inbox)URL + ip: IP 地址 location: all: 全部 local: 本地 remote: 远程 - title: 地点 + title: 位置 media_attachments: 媒体文件 moderation: all: 全部 - silenced: 被静音的 - suspended: 被停权的 - title: 管理操作 - most_recent_activity: 最新活动 - most_recent_ip: 最新 IP 地址 + silenced: 已静音 + suspended: 已封禁 + title: 帐户状态 + moderation_notes: 管理记录 + most_recent_activity: 最后一次活跃的时间 + most_recent_ip: 最后一次活跃的 IP 地址 not_subscribed: 未订阅 order: alphabetic: 按字母 most_recent: 按时间 title: 排序 - perform_full_suspension: 实行完全暂停 - profile_url: 个人文件 URL - public: 公共 - push_subscription_expires: 推送订阅过期 + outbox_url: 发件箱(Outbox)URL + perform_full_suspension: 永久封禁 + profile_url: 个人资料页面 URL + protocol: 协议 + public: 公开页面 + push_subscription_expires: PuSH 订阅过期时间 + redownload: 刷新头像 reset: 重置 reset_password: 重置密码 - salmon_url: Salmon 反馈 URL + resubscribe: 重新订阅 + salmon_url: Salmon URL search: 搜索 + shared_inbox_url: 公用收件箱(Shared Inbox)URL show: - created_reports: 这个帐户创建的报告 - report: 报告 - targeted_reports: 关于这个帐户的报告 + created_reports: 这个帐户提交的举报 + report: 个举报 + targeted_reports: 针对这个帐户的举报 silence: 静音 statuses: 嘟文 + subscribe: 订阅 title: 用户 undo_silenced: 解除静音 - undo_suspension: 解除停权 - username: 用户名称 - web: 用户页面 + undo_suspension: 解除封禁 + unsubscribe: 取消订阅 + username: 用户名 + web: 站内页面 + custom_emojis: + copied_msg: 成功将表情复制到本地 + copy: 复制 + copy_failed_msg: 无法将表情复制到本地 + created_msg: 表情添加成功! + delete: 删除 + destroyed_msg: 表情删除成功! + disable: 停用 + disabled_msg: 表情停用成功 + emoji: 表情 + enable: 启用 + enabled_msg: 表情启用成功 + image_hint: PNG 格式,最大 50KB + listed: 默认显示的表情 + new: + title: 添加新的自定义表情 + shortcode: 短代码 + shortcode_hint: 至少 2 个字符,只能使用字母、数字和下划线 + title: 自定义表情 + unlisted: 默认隐藏的表情 + update_failed_msg: 表情更新失败! + updated_msg: 表情更新成功! + upload: 上传 domain_blocks: add_new: 添加 - created_msg: 正处理域名阻隔 - destroyed_msg: 已撤销域名阻隔 - domain: 域名阻隔 + created_msg: 正在进行域名屏蔽 + destroyed_msg: 域名屏蔽已撤销 + domain: 域名 new: - create: 添加域名阻隔 - hint: "「域名阻隔」不会隔绝该域名用户的嘟帐户入本站数据库,但会嘟文抵达后,自动套用特定的审批操作。" + create: 添加域名屏蔽 + hint: 域名屏蔽不会阻止该域名下的帐户进入本站的数据库,但是会对来自这个域名的帐户自动进行预先设置的管理操作。 severity: - desc_html: "「自动静音」令该域名用户的嘟文,设为只对关注者显示,没有关注的人会看不到。 「自动除名」会自动将该域名用户的嘟文、媒体文件、个人资料从本服务器实例删除。" + desc_html: 选择自动静音会将该域名下帐户发送的嘟文设置为仅关注者可见;选择自动封禁会将该域名下帐户发送的嘟文、媒体文件以及个人资料数据从本实例上删除;选择可以拒绝接收来自该域名的任何媒体文件。 + noop: 无 silence: 自动静音 - suspend: 自动除名 - title: 添加域名阻隔 - reject_media: 拒绝媒体文件 - reject_media_hint: 删除本地缓存的媒体文件,再也不在未来下载这个站点的文件。和自动除名无关。 + suspend: 自动封禁 + title: 添加域名屏蔽 + reject_media: 拒绝接收媒体文件 + reject_media_hint: 删除本地已缓存的媒体文件,并且不再接收来自该域名的任何媒体文件。此选项不影响封禁 severities: + noop: 无 silence: 自动静音 - suspend: 自动除名 - severity: 阻隔程度 + suspend: 自动封禁 + severity: 封禁级别 show: - affected_accounts: - one: 数据库中有1个帐户受影响 - other: 数据库中有%{count}个帐户受影响 + affected_accounts: 将会影响到数据库中的 %{count} 个帐户 retroactive: silence: 对此域名的所有帐户取消静音 - suspend: 对此域名的所有帐户取消除名 - title: 撤销 %{domain} 的域名阻隔 + suspend: 对此域名的所有帐户取消封禁 + title: 撤销对 %{domain} 的域名屏蔽 undo: 撤销 - title: 域名阻隔 + title: 域名屏蔽 undo: 撤销 + email_domain_blocks: + add_new: 添加新条目 + created_msg: 电子邮件域名屏蔽添加成功 + delete: 删除 + destroyed_msg: 电子邮件域名屏蔽删除成功 + domain: 域名 + new: + create: 添加封禁 + title: 添加电子邮件域名屏蔽 + title: 电子邮件域名屏蔽 instances: - account_count: 已知帐号 + account_count: 已知帐户 domain_name: 域名 + reset: 重置 + search: 搜索 title: 已知实例 reports: - are_you_sure: 你确定吗? + action_taken_by: 操作执行者 + are_you_sure: 你确定吗? comment: label: 备注 none: 没有 delete: 删除 id: ID - mark_as_resolved: 标示为「已处理」 + mark_as_resolved: 标记为“已处理” nsfw: - 'false': NSFW无效 - 'true': NSFW有效 + 'false': 取消 NSFW 标记 + 'true': 添加 NSFW 标记 report: '举报 #%{id}' + report_contents: 内容 reported_account: 举报用户 - reported_by: 举报者 + reported_by: 举报人 resolved: 已处理 - silence_account: 将用户静音 + silence_account: 静音用户 status: 状态 - suspend_account: 将用户停权 - target: 对象 + suspend_account: 封禁用户 + target: 被举报人 title: 举报 unresolved: 未处理 view: 查看 settings: + bootstrap_timeline_accounts: + desc_html: 用半角逗号分隔多个用户名。只能添加来自本站且未开启保护的帐户。如果留空,则默认关注本站所有的管理员。 + title: 新用户默认关注 contact_information: - email: 输入一个公开的电邮地址 - username: 输入用户名称 + email: 输入一个公开的电子邮件地址 + username: 输入用户名 registrations: closed_message: - desc_html: 当本站暂停接受注册时,会显示这个消息。
可使用 HTML - title: 暂停注册消息 + desc_html: 本站关闭注册期间的提示信息。可以使用 HTML 标签 + title: 关闭注册时的提示消息 + deletion: + desc_html: 允许所有人删除自己的帐户 + title: 开放删除帐户权限 open: + desc_html: 允许任何人建立一个帐户 title: 开放注册 site_description: - desc_html: 在首页显示,及在 meta 标签中用作网站介绍。
你可以在此使用 HTML 标签,尤其是<a><em>。 - title: 本站介绍 + desc_html: 展示在首页以及 meta 标签中的网站简介。可以使用 HTML 标签,包括 <a><em>。 + title: 本站简介 site_description_extended: - desc_html: 本站详细信息页的內容
你可在此使用 HTML - title: 本站详细信息 + desc_html: 可以填写行为守则、规定、指南或其他本站特有的内容。可以使用 HTML 标签 + title: 本站详细介绍 + site_terms: + desc_html: 可以填写自己的隐私权政策、使用条款或其他法律文本。可以使用 HTML 标签 + title: 自定义使用条款 site_title: 本站名称 + thumbnail: + desc_html: 用于在 OpenGraph 和 API 中显示预览图。推荐分辨率 1200×630px + title: 本站缩略图 + timeline_preview: + desc_html: 在主页显示公开时间线 + title: 时间线预览 title: 网站设置 + statuses: + back_to_account: 返回帐户信息页 + batch: + delete: 删除 + nsfw_off: 取消 NSFW 标记 + nsfw_on: 添加 NSFW 标记 + execute: 执行 + failed_to_execute: 执行失败 + media: + hide: 隐藏媒体文件 + show: 显示媒体文件 + title: 媒体文件 + no_media: 不含媒体文件 + title: 帐户嘟文 + with_media: 含有媒体文件 subscriptions: callback_url: 回调 URL - confirmed: 确定 - expires_in: 期限 - last_delivery: 数据最后送抵时间 - title: WebSub 订阅 - topic: 所订阅资源 + confirmed: 已确认 + expires_in: 失效时间 + last_delivery: 最后一次接收数据的时间 + title: WebSub + topic: Topic title: 管理 + admin_mailer: + new_report: + body: "%{reporter} 举报了 %{target}" + subject: 来自 %{instance} 的新举报(#%{id}) application_mailer: - settings: 更改电邮设置︰%{link} + salutation: "%{name}," + settings: 更改电子邮件首选项:%{link} signature: 来自 %{instance} 的 Mastodon 通知 view: 查看: applications: + created: 应用创建成功 + destroyed: 应用删除成功 invalid_url: URL 无效 + regenerate_token: 重置访问令牌 + token_regenerated: 访问令牌重置成功 + warning: 一定小心,千万不要把它分享给任何人! + your_token: 你的访问令牌 auth: - change_password: 登录凭据 + agreement_html: 注册即表示你同意我们的使用条款隐私权政策。 + change_password: 帐户安全 + delete_account: 删除帐户 + delete_account_html: 如果你想删除你的帐户,请点击这里继续。你需要确认你的操作。 didnt_get_confirmation: 没有收到确认邮件? forgot_password: 忘记密码? + invalid_reset_password_token: 密码重置令牌无效或已过期。请重新发起重置密码请求。 login: 登录 logout: 登出 register: 注册 - resend_confirmation: 重发确认邮件 + resend_confirmation: 重新发送确认邮件 reset_password: 重置密码 set_new_password: 设置新密码 authorize_follow: error: 对不起,寻找这个跨站用户时出错 follow: 关注 + follow_request: 关注请求已发送给: + following: 成功!你正在关注: + post_follow: + close: 你也可以直接关闭这个窗口。 + return: 返回至个人资料页 + web: 返回本站 title: 关注 %{acct} datetime: distance_in_words: - about_x_hours: "%{count} 小时" + about_x_hours: "%{count} 时" about_x_months: "%{count} 个月" about_x_years: "%{count} 年" - almost_x_years: 接近 %{count} 年 + almost_x_years: "%{count} 年" half_a_minute: 刚刚 - less_than_x_minutes: "%{count} 分不到" + less_than_x_minutes: "%{count} 分" less_than_x_seconds: 刚刚 - over_x_years: 超过 %{count} 年 + over_x_years: "%{count} 年" x_days: "%{count} 天" x_minutes: "%{count} 分" x_months: "%{count} 个月" x_seconds: "%{count} 秒" + deletes: + bad_password_msg: 想得美,黑客!密码输入错误 + confirm_password: 输入你当前的密码来验证身份 + description_html: 继续操作将会永久地、不可撤销地删除你帐户中的内容,并冻结你的帐户。你的用户名将会被保留,以防有人冒用你的身份。 + proceed: 删除帐户 + success_msg: 你的帐户已经成功删除 + warning_html: 我们只能保证本实例上的内容已经被彻底删除。对于已经被广泛传播的内容,它们在本实例以外的某些地方可能仍然可见。此外,失去连接的服务器以及停止接收订阅的服务器上的数据亦无法删除。 + warning_title: 关于已传播的内容的警告 errors: '403': 无权查看 '404': 找不到页面 @@ -199,68 +338,70 @@ zh-CN: content: 无法确认登录信息。你是不是屏蔽了 Cookie? title: 无法确认登录信息 '429': 被限制 + '500': + content: 抱歉,我们这里出错了。 + title: 这个页面不正确 + noscript_html: 请启用 JavaScript 以便使用 Mastodon 网页版应用。你也可以选择适用于你的平台的 Mastodon 应用。 exports: - blocks: 被你封锁的用户 + blocks: 屏蔽的用户 csv: CSV - follows: 你所关注的用户 - mutes: 你所静音的用户 - storage: 媒体容量大小 + follows: 关注的用户 + mutes: 静音的用户 + storage: 媒体文件存储 followers: domain: 域名 - explanation_html: 想要保护你的嘟文的话,请慎重考虑关注你的人。你的受保护的嘟文会发送到有你的关注者的所有实例上。你也许想要复查一下关注者列表来移除那些你无法信任的关注者。 + explanation_html: 为保证你的嘟文的隐私安全,你应当时刻留意你的关注者列表。受保护的嘟文将会发送到所有关注者所在的实例上。有些实例使用的软件代码或其管理员可能不会尊重你的隐私设置,因此你应当复查一下关注者列表,并移除那些你无法信任的关注者。 followers_count: 关注者数量 - lock_link: 保护你的帐户 + lock_link: 为你的帐户开启保护 purge: 从关注者中移除 - success: 从 %{count} 个域名中移除了关注者。 - true_privacy_html: "真正的隐私只能靠端到端加密来实现!" - unlocked_warning_html: 任何人都可以关注你然后查看被保护的嘟文, %{lock_link} 可以复核和拒绝关注请求。 - unlocked_warning_title: 你的帐户没被保护 + success: 正在从 %{count} 个域名中移除关注者…… + true_privacy_html: 请始终铭记:真正的隐私只能靠端到端加密来实现! + unlocked_warning_html: 任何人都可以通过关注你来立即查看被保护的嘟文。%{lock_link},即可审核并拒绝关注请求。 + unlocked_warning_title: 你的帐户未受到保护 generic: - changes_saved_msg: 更改已被保存。 + changes_saved_msg: 更改保存成功! powered_by: 基于 %{link} 构建 - save_changes: 保存 + save_changes: 保存更改 validation_errors: - one: 出错啦!请确认以下出错的地方,修改之后再来一次: - other: 出错啦!请确认以下 %{count} 处出错的地方,修改之后再来一次: + one: 出错啦!检查一下下面出错的地方吧 + other: 出错啦!检查一下下面 %{count} 处出错的地方吧 imports: - preface: 你可以在此导入你在其他服务器实例所导出的数据文件,包括︰你所关注、封锁的用户。 - success: 你已成功上载数据文件,我们正将数据导入,请稍候 + preface: 你可以在此导入你在其他实例导出的数据,比如你所关注或屏蔽的用户列表。 + success: 数据上传成功,正在处理中 types: - blocking: 封锁名单 - following: 关注名单 - muting: 静音名单 - upload: 上载 - landing_strip_html: "%{name} 是一个在 %{link_to_root_path} 的用户。只要你是象毛世界里(Mastodon、GNU social)任一服务器实例的用户,便可以跨站关注此站用户并与其沟通。" - landing_strip_signup_html: 如果你没有这类帐户,欢迎在此处登记。 + blocking: 屏蔽列表 + following: 关注列表 + muting: 静音列表 + upload: 上传 + landing_strip_html: "%{name} 是一位来自 %{link_to_root_path} 的用户。如果你想关注这个人或者与这个人互动,你需要在任意一个 Mastodon 实例或与其兼容的网站上拥有一个帐户。" + landing_strip_signup_html: 还没有这种帐户?你可以在本站注册一个。 media_attachments: validations: - images_and_video: 无法添加视频到一个已经包含图片的嘟文中 - too_many: 最多只能添加4张图片 + images_and_video: 无法在嘟文中同时插入视频和图片 + too_many: 最多只能添加 4 张图片 notification_mailer: digest: - body: 自从你在%{since}使用%{instance}以后,错过了这些嘟嘟滴滴: - mention: "%{name} 在此提及了你︰" + body: 自从你最后一次(时间是%{since})登录 %{instance} 以来,你错过了这些嘟嘟滴滴: + mention: "%{name} 在嘟文中提到了你:" new_followers_summary: - one: 有人关注你了!耶! - other: 有 %{count} 个人关注了你!别激动! - subject: - one: "你有一个新通知 \U0001F418" - other: "%{count} 个通知太多,赶快去看看 \U0001F418" + one: 有个人关注了你!耶! + other: 有 %{count} 个人关注了你!好棒! + subject: "自从你最后一次登录以来,你错过了 %{count} 条新通知 \U0001F418" favourite: - body: "%{name} 收藏了你" - subject: "%{name} 给你点了收藏" + body: 你的嘟文被 %{name} 收藏了: + subject: "%{name} 收藏了你的嘟文" follow: - body: "%{name} 关注了你" + body: "%{name} 关注了你!" subject: "%{name} 关注了你" follow_request: - body: "%{name} 要求关注你" - subject: 等候关注你的用户︰ %{name} + body: "%{name} 请求关注你" + subject: 待审核的关注者:%{name} mention: - body: "%{name} 在文章中提及你︰" - subject: "%{name} 在文章中提及你" + body: "%{name} 在嘟文中提到了你:" + subject: "%{name} 提到了你" reblog: - body: 你的嘟文得到 %{name} 的转嘟 - subject: "%{name} 转嘟(嘟嘟滴)了你的嘟文" + body: 你的嘟文被 %{name} 转嘟了: + subject: "%{name} 转嘟了你的嘟文" number: human: decimal_units: @@ -275,54 +416,197 @@ zh-CN: pagination: next: 下一页 prev: 上一页 - truncate: "……" + truncate: "…" + preferences: + languages: 语言 + other: 其他 + publishing: 发布 + web: 站内 + push_notifications: + favourite: + title: "%{name} 收藏了你的嘟文" + follow: + title: "%{name} 关注了你" + group: + title: "%{count} 条新通知" + mention: + action_boost: 转嘟 + action_expand: 显示更多 + action_favourite: 收藏 + title: "%{name} 提到了你" + reblog: + title: "%{name} 转嘟了你的嘟文" remote_follow: - acct: 请输入你的︰用户名称@实例域名 - missing_resource: 无法找到您的帐户转接网址 - proceed: 下一步 - prompt: 你正准备关注︰ + acct: 请输入你的“用户名@实例域名” + missing_resource: 无法确定你的帐户的跳转 URL + proceed: 确认关注 + prompt: 你正准备关注: + sessions: + activity: 最后一次活跃的时间 + browser: 浏览器 + browsers: + alipay: 支付宝 + blackberry: Blackberry + chrome: Chrome + edge: Microsoft Edge + firefox: Firefox + generic: 未知浏览器 + ie: Internet Explorer + micro_messenger: 微信 + nokia: Nokia S40 Ovi 浏览器 + opera: Opera + phantom_js: PhantomJS + qq: QQ浏览器 + safari: Safari + uc_browser: UC浏览器 + weibo: 新浪微博 + current_session: 当前会话 + description: "%{platform} 上的 %{browser}" + explanation: 你的 Mastodon 帐户目前已在这些浏览器上登录。 + ip: IP 地址 + platforms: + adobe_air: Adobe Air + android: Android + blackberry: Blackberry + chrome_os: ChromeOS + firefox_os: Firefox OS + ios: iOS + linux: Linux + mac: Mac + other: 未知平台 + windows: Windows + windows_mobile: Windows Mobile + windows_phone: Windows Phone + revoke: 注销 + revoke_success: 会话注销成功 + title: 会话 settings: authorized_apps: 已授权的应用 back: 回到 Mastodon + delete: 删除帐户 + development: 开发 edit_profile: 更改个人信息 export: 导出 followers: 授权的关注者 import: 导入 + notifications: 通知 preferences: 首选项 settings: 设置 two_factor_authentication: 两步认证 + your_apps: 你的应用 statuses: - open_in_web: 打开网页 + open_in_web: 在站内打开 over_character_limit: 超过了 %{max} 字的限制 + pin_errors: + limit: 置顶的嘟文条数超出限制 + ownership: 不能置顶他人的嘟文 + private: 不能置顶非公开的嘟文 + reblog: 不能置顶转嘟 show_more: 显示更多 visibilities: - private: 限关注者 - private_long: 仅向关注者公开 + private: 仅关注者 + private_long: 只有关注你的用户能看到 public: 公开 - public_long: 向所有人公开 - unlisted: 于公共时间线中隐藏 - unlisted_long: 公开,但不显示在公共时间线中 + public_long: 所有人可见,并会出现在公共时间轴上 + unlisted: 不公开 + unlisted_long: 所有人可见,但不会出现在公共时间轴上 stream_entries: - click_to_show: 显示 + click_to_show: 点击显示 + pinned: 置顶嘟文 reblogged: 转嘟 sensitive_content: 敏感内容 + terms: + body_html: | +

隐私权政策

+ +

我们收集什么信息?

+ +

我们从你在我们站点注册开始从你那开始收集信息,并收集关于你在论坛的阅读和写作的数据,并评估分享的内容。

+ +

当在我们站点注册时,你可能被要求输入你的名字和邮件地址。然而你可以在不用注册的情况下访问站点。你的邮件地将通过一个独一无二的链接验证。如果链接被访问了,我们就知道你控制了该邮件地址。

+ +

当已注册和发帖时,我们记录发布帖子时的 IP 地址。我们也可能保留服务器日志,其中包括了每一个向我们服务器的请求。

+ +

我们如何使用你的信息?

+ +

从你那收集的任何数据将以以下方式使用:

+ +
    +
  • 改进你的个人体验 — 你的信息帮助我们更好地满足你的个人需求。
  • +
  • 改进我们的站点 — 我们基于信息和我们从你那收到的反馈不断地试图改进我们的站点。
  • +
  • 改善我们的客户服务 — 你的信息帮助我们更有效地回应用户服务请求和支持。
  • +
  • 用于发送阶段性的邮件 — 你提供的邮件地址可能用于接受信息、你想看到的通知或与你用户名有关的回复和询问,或是其他的请求和问题。
  • +
+ +

我们如何保护你的信息?

+ +

我们实现了一系列的安全措施保证你输入、提交或者访问你个人信息的数据安全。

+ +

数据保存政策是什么?

+ +

我们将善意地:

+ +
    +
  • 保存 90 天内的所有向服务器的包含 IP 地址的请求。
  • +
  • 保存 5 年内已注册用户和与他们的帖子有关的 IP 地址。
  • +
+ +

我们使用 Cookie 吗?

+ +

是的。Cookie 是网站或它的服务商通过网页浏览器存储在你电脑硬盘上的小文件(如果你同意)。这些 Cookie 使站点能分辨你的浏览器,并且,如果你注册了一个账户,与你的注册账户关联。

+ +

我们使用 Cookie 为之后的访问和编译一小段关于站点流量和交互的数据来判断并保存你的个人设置,这样我们可以在之后提供更好的站点体验和工具。我们可能使用第三方服务商来帮助我们更好地理解我们的站点访客。这些服务商是不允许代表我们使用收集的信息,除非是在帮助我们执行和改进我们的站点。

+ +

我们会在站外提供任何信息吗?

+ +

我们绝不销售、交易或任何向外转移你个人信息的行为。这不包括帮助我们管理站点、改进站点或给你提供服务的第三方团体,这些团体需要保证对这些信息保密。当我们认为提交你的信息符合法律、我们的站点政策或保护我们或其他人的权利、知识产权或安全时,我们也可能提交你的信息。然而,非个人访问信息可能供其他团体使用,用于市场、广告或其他用途。

+ +

第三方链接

+ +

偶尔地,根据我们的判断,我们可能在我们的站点上包括或提供第三方团体的产品或服务。这些第三方站点用于独立和不同的隐私政策。因此我们对链接到的站点或活动没有责任和权利。尽管如此,我们寻求保护我们的整个站点并且欢迎你给这些站点反馈。

+ +

儿童在线隐私保护法案合规

+ +

我们的站点、产品和服务提供给 13 岁以上的人们。如果服务器位于美国,并且你小于 13 岁,根据儿童在线隐私保护法案合规,不要使用这个站点。

+ +

仅用于在线隐私政策

+ +

这个线上隐私政策只适用于通过我们站点收集到的信息,并不包括线下收集的信息。

+ + + +

你使用站点的同时,代表你同意了我们网站的隐私政策。

+ +

隐私政策的更改

+ +

如果我们决定更改我们的隐私政策,我们将在此页更新这些改变。

+ +

文档以 CC-BY-SA 发布。最后更新时间为2013年5月31日。

+ +

原文出自 Discourse 隐私权政策

+ title: "%{instance} 使用条款和隐私权政策" + themes: + default: Mastodon time: formats: - default: "%Y年%-m月%d日 %H:%M" + default: "%Y年%-m月%d日%H:%M" two_factor_authentication: - code_hint: 请输入你认证器产生的代码,以确认设置 - description_html: 当你启用两步认证后,你登录时将额外需要使用手机或其他认证器生成的代码。 + code_hint: 输入你的认证器生成的代码以确认 + description_html: 启用两步认证后,你需要输入手机认证器生成的代码才能登录 disable: 停用 enable: 启用 - enabled_success: 已成功启用两步认证 + enabled: 两步认证已启用 + enabled_success: 两步认证启用成功 generate_recovery_codes: 生成恢复代码 - instructions_html: "请用你手机的认证器应用(如 Google Authenticator、Authy),扫描这里的 QR 二维码。在两步认证启用后,你登录时将需要使用此应用程序产生的认证码。" - lost_recovery_codes: 如果你丢了手机,你可以用恢复代码重新访问你的帐户。如果你丢了恢复代码,也可以在这里重新生成一个,不过以前的恢复代码就失效了。(废话) - manual_instructions: 如果你无法扫描 QR 二维码,请手动输入这个文本密码︰ - recovery_codes_regenerated: 已成功重新生成恢复代码 - recovery_instructions_html: 如果你的手机无法使用,你可以使用下面的任何恢复代码来恢复你的帐号。请保管好你的恢复代码以防泄漏(例如你可以打印好它们并和重要文档一起保存)。 + instructions_html: "请使用 Google 身份验证器或其他类似的 TOTP 两步验证手机应用扫描此处的二维码。启用两部验证后,你需要输入该应用生成的代码来登录你的帐户。" + lost_recovery_codes: 如果你的手机不慎丢失,你可以使用恢复代码来重新获得对帐户的访问权。如果你遗失了恢复代码,可以在此处重新生成。之前使用的恢复代码将会失效。 + manual_instructions: 如果你无法扫描二维码,请手动输入下列文本: + recovery_codes: 备份恢复代码 + recovery_codes_regenerated: 恢复代码重新生成成功 + recovery_instructions_html: 如果你的手机无法使用,你可以使用下列任意一个恢复代码来重新获得对帐户的访问权。请妥善保管好你的恢复代码(例如,你可以将它们打印出来,然后和其他重要的文件放在一起)。 setup: 设置 - wrong_code: 你输入的认证码并不正确!可能服务器时间和你手机不一致,请检查你手机的时钟,或与本站管理员联系。 + wrong_code: 输入的认证码无效!请检查你设备上显示的时间是否正确,如果正确,你可能需要联系管理员以检查服务器的时间是否正确。 users: - invalid_email: 邮箱格式有误 - invalid_otp_token: 两步认证码有误 + invalid_email: 输入的电子邮件地址无效 + invalid_otp_token: 输入的两步认证代码无效 + signed_in_as: 当前登录的帐户: -- cgit From a2a4bf4e782017b0b599f6d9119643339a7ba7a2 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Tue, 31 Oct 2017 20:22:32 +0900 Subject: Update dependencies for Ruby (2017-10-30) (#5566) * Update better_errors to version 2.4.0 * Update binding_of_caller to version 0.7.3 * Update bootsnap to version 1.1.5 * Update browser to version 2.5.2 * Update capistrano to version 3.10.0 * Update capistrano-bundler to version 1.3.0 * Update capistrano-rbenv to version 2.1.2 * Update capybara to version 2.15.4 * Update cld3 to version 3.2.1 * Update fabrication to version 2.18.0 * Update fog-openstack to version 0.1.22 * Update kaminari to version 1.1.1 * Update lograge to version 0.7.1 * Update nokogiri to version 1.8.1 * Update oj to version 3.3.9 * Update ox to version 2.8.1 * Update parallel_tests to version 2.17.0 * Update pkg-config to version 1.2.8 * Update rspec-rails to version 3.7.1 * Update rubocop to version 0.51.0 * Update scss_lint to version 0.55.0 * Update sidekiq to version 5.0.5 * Update sidekiq-scheduler to version 2.1.10 * Update tzinfo-data to version 1.2017.3 * Update webpacker to version 3.0.2 * bundle update --- Gemfile | 26 +++---- Gemfile.lock | 186 ++++++++++++++++++++++++------------------------- bin/webpack | 36 ++++------ bin/webpack-dev-server | 83 +++++----------------- config/deploy.rb | 2 +- 5 files changed, 136 insertions(+), 197 deletions(-) (limited to 'config') diff --git a/Gemfile b/Gemfile index 7b359af1d..e535372f9 100644 --- a/Gemfile +++ b/Gemfile @@ -38,14 +38,14 @@ gem 'http', '~> 2.2' gem 'http_accept_language', '~> 2.1' gem 'httplog', '~> 0.99' gem 'idn-ruby', require: 'idn' -gem 'kaminari', '~> 1.0' +gem 'kaminari', '~> 1.1' gem 'link_header', '~> 0.0' gem 'mime-types', '~> 3.1' -gem 'nokogiri', '~> 1.7' +gem 'nokogiri', '~> 1.8' gem 'nsa', '~> 0.2' -gem 'oj', '~> 3.0' +gem 'oj', '~> 3.3' gem 'ostatus2', '~> 2.0' -gem 'ox', '~> 2.5' +gem 'ox', '~> 2.8' gem 'pundit', '~> 1.1' gem 'rabl', '~> 0.13' gem 'rack-attack', '~> 5.0' @@ -75,15 +75,15 @@ gem 'json-ld-preloaded', '~> 2.2.1' gem 'rdf-normalize', '~> 0.3.1' group :development, :test do - gem 'fabrication', '~> 2.16' + gem 'fabrication', '~> 2.18' gem 'fuubar', '~> 2.2' gem 'i18n-tasks', '~> 0.9', require: false gem 'pry-rails', '~> 0.3' - gem 'rspec-rails', '~> 3.6' + gem 'rspec-rails', '~> 3.7' end group :test do - gem 'capybara', '~> 2.14' + gem 'capybara', '~> 2.15' gem 'climate_control', '~> 0.2' gem 'faker', '~> 1.7' gem 'microformats', '~> 4.0' @@ -91,13 +91,13 @@ group :test do gem 'rspec-sidekiq', '~> 3.0' gem 'simplecov', '~> 0.14', require: false gem 'webmock', '~> 3.0' - gem 'parallel_tests', '~> 2.14' + gem 'parallel_tests', '~> 2.17' end group :development do gem 'active_record_query_trace', '~> 1.5' gem 'annotate', '~> 2.7' - gem 'better_errors', '~> 2.1' + gem 'better_errors', '~> 2.4' gem 'binding_of_caller', '~> 0.7' gem 'bullet', '~> 5.5' gem 'letter_opener', '~> 1.4' @@ -105,15 +105,15 @@ group :development do gem 'rubocop', require: false gem 'brakeman', '~> 4.0', require: false gem 'bundler-audit', '~> 0.6', require: false - gem 'scss_lint', '~> 0.53', require: false + gem 'scss_lint', '~> 0.55', require: false - gem 'capistrano', '~> 3.8' - gem 'capistrano-rails', '~> 1.2' + gem 'capistrano', '~> 3.10' + gem 'capistrano-rails', '~> 1.3' gem 'capistrano-rbenv', '~> 2.1' gem 'capistrano-yarn', '~> 2.0' end group :production do - gem 'lograge', '~> 0.5' + gem 'lograge', '~> 0.7' gem 'redis-rails', '~> 5.0' end diff --git a/Gemfile.lock b/Gemfile.lock index 14ed0d309..b4b3d05cc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -57,25 +57,25 @@ GEM encryptor (~> 3.0.0) av (0.9.0) cocaine (~> 0.5.3) - aws-sdk (2.10.46) - aws-sdk-resources (= 2.10.46) - aws-sdk-core (2.10.46) + aws-sdk (2.10.73) + aws-sdk-resources (= 2.10.73) + aws-sdk-core (2.10.73) aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-resources (2.10.46) - aws-sdk-core (= 2.10.46) + aws-sdk-resources (2.10.73) + aws-sdk-core (= 2.10.73) aws-sigv4 (1.0.2) bcrypt (3.1.11) - better_errors (2.3.0) + better_errors (2.4.0) coderay (>= 1.0.0) erubi (>= 1.0.0) rack (>= 0.9.0) - binding_of_caller (0.7.2) + binding_of_caller (0.7.3) debug_inspector (>= 0.0.1) - bootsnap (1.1.3) + bootsnap (1.1.5) msgpack (~> 1.0) brakeman (4.0.1) - browser (2.5.1) + browser (2.5.2) builder (3.2.3) bullet (5.6.1) activesupport (>= 3.0.0) @@ -83,23 +83,23 @@ GEM bundler-audit (0.6.0) bundler (~> 1.2) thor (~> 0.18) - capistrano (3.9.1) + capistrano (3.10.0) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) sshkit (>= 1.9.0) - capistrano-bundler (1.2.0) + capistrano-bundler (1.3.0) capistrano (~> 3.1) sshkit (~> 1.2) capistrano-rails (1.3.0) capistrano (~> 3.1) capistrano-bundler (~> 1.1) - capistrano-rbenv (2.1.1) + capistrano-rbenv (2.1.2) capistrano (~> 3.1) sshkit (~> 1.3) capistrano-yarn (2.0.2) capistrano (~> 3.0) - capybara (2.15.1) + capybara (2.15.4) addressable mini_mime (>= 0.1.3) nokogiri (>= 1.3.3) @@ -110,7 +110,7 @@ GEM activesupport charlock_holmes (0.7.5) chunky_png (1.3.8) - cld3 (3.2.0) + cld3 (3.2.1) ffi (>= 1.1.0, < 1.10.0) climate_control (0.2.0) cocaine (0.5.8) @@ -150,12 +150,12 @@ GEM thread thread_safe encryptor (3.0.0) - erubi (1.6.1) - et-orbi (1.0.5) + erubi (1.7.0) + et-orbi (1.0.8) tzinfo excon (0.59.0) execjs (2.7.0) - fabrication (2.16.3) + fabrication (2.18.0) faker (1.8.4) i18n (~> 0.5) fast_blank (1.0.0) @@ -167,7 +167,7 @@ GEM fog-json (1.0.2) fog-core (~> 1.0) multi_json (~> 1.10) - fog-openstack (0.1.21) + fog-openstack (0.1.22) fog-core (>= 1.40) fog-json (>= 1.0) ipaddress (>= 0.8) @@ -175,7 +175,7 @@ GEM fuubar (2.2.0) rspec-core (~> 3.0) ruby-progressbar (~> 1.4) - globalid (0.4.0) + globalid (0.4.1) activesupport (>= 4.2.0) goldfinger (2.0.1) addressable (~> 2.5) @@ -211,7 +211,8 @@ GEM httplog (0.99.7) colorize rack - i18n (0.8.6) + i18n (0.9.0) + concurrent-ruby (~> 1.0) i18n-tasks (0.9.18) activesupport (>= 4.0.2) ast (>= 2.1.0) @@ -227,27 +228,27 @@ GEM iso-639 (0.2.8) jmespath (1.3.1) json (2.1.0) - json-ld (2.1.5) + json-ld (2.1.7) multi_json (~> 1.12) - rdf (~> 2.2) + rdf (~> 2.2, >= 2.2.8) json-ld-preloaded (2.2.2) json-ld (~> 2.1, >= 2.1.5) multi_json (~> 1.11) rdf (~> 2.2) jsonapi-renderer (0.1.3) - jwt (1.5.6) - kaminari (1.0.1) + jwt (2.1.0) + kaminari (1.1.1) activesupport (>= 4.1.0) - kaminari-actionview (= 1.0.1) - kaminari-activerecord (= 1.0.1) - kaminari-core (= 1.0.1) - kaminari-actionview (1.0.1) + kaminari-actionview (= 1.1.1) + kaminari-activerecord (= 1.1.1) + kaminari-core (= 1.1.1) + kaminari-actionview (1.1.1) actionview - kaminari-core (= 1.0.1) - kaminari-activerecord (1.0.1) + kaminari-core (= 1.1.1) + kaminari-activerecord (1.1.1) activerecord - kaminari-core (= 1.0.1) - kaminari-core (1.0.1) + kaminari-core (= 1.1.1) + kaminari-core (1.1.1) launchy (2.4.3) addressable (~> 2.3) letter_opener (1.4.1) @@ -257,18 +258,19 @@ GEM letter_opener (~> 1.0) railties (>= 3.2) link_header (0.0.8) - lograge (0.6.0) + lograge (0.7.1) actionpack (>= 4, < 5.2) activesupport (>= 4, < 5.2) railties (>= 4, < 5.2) request_store (~> 1.0) - loofah (2.0.3) + loofah (2.1.1) + crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.6.6) mime-types (>= 1.16, < 4) mario-redis-lock (1.2.0) redis (~> 3, >= 3.0.5) - method_source (0.8.2) + method_source (0.9.0) microformats (4.0.7) json nokogiri @@ -277,7 +279,7 @@ GEM mime-types-data (3.2016.0521) mimemagic (0.3.2) mini_mime (0.1.4) - mini_portile2 (2.2.0) + mini_portile2 (2.3.0) minitest (5.10.3) msgpack (1.1.0) multi_json (1.12.2) @@ -285,8 +287,8 @@ GEM net-ssh (>= 2.6.5) net-ssh (4.2.0) nio4r (2.1.0) - nokogiri (1.8.0) - mini_portile2 (~> 2.2.0) + nokogiri (1.8.1) + mini_portile2 (~> 2.3.0) nokogumbo (1.4.13) nokogiri nsa (0.2.4) @@ -294,15 +296,15 @@ GEM concurrent-ruby (~> 1.0.0) sidekiq (>= 3.5.0) statsd-ruby (~> 1.2.0) - oj (3.3.5) - openssl (2.0.5) + oj (3.3.9) + openssl (2.0.6) orm_adapter (0.5.0) ostatus2 (2.0.1) addressable (~> 2.4) http (~> 2.0) nokogiri (~> 1.6) openssl (~> 2.0) - ox (2.6.0) + ox (2.8.1) paperclip (5.1.0) activemodel (>= 4.2.0) activesupport (>= 4.2.0) @@ -313,19 +315,18 @@ GEM av (~> 0.9.0) paperclip (>= 2.5.2) parallel (1.12.0) - parallel_tests (2.15.0) + parallel_tests (2.17.0) parallel parser (2.4.0.0) ast (~> 2.2) pg (0.21.0) pghero (1.7.0) activerecord - pkg-config (1.2.7) + pkg-config (1.2.8) powerpack (0.1.1) - pry (0.10.4) + pry (0.11.2) coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) + method_source (~> 0.9.0) pry-rails (0.3.6) pry (>= 0.10.4) public_suffix (3.0.0) @@ -379,31 +380,31 @@ GEM thor (>= 0.18.1, < 2.0) rainbow (2.2.2) rake - rake (12.1.0) - rdf (2.2.9) + rake (12.2.1) + rdf (2.2.11) hamster (~> 3.0) link_header (~> 0.0, >= 0.0.8) rdf-normalize (0.3.2) rdf (~> 2.0) - redis (3.3.3) - redis-actionpack (5.0.1) + redis (3.3.5) + redis-actionpack (5.0.2) actionpack (>= 4.0, < 6) redis-rack (>= 1, < 3) - redis-store (>= 1.1.0, < 1.4.0) - redis-activesupport (5.0.3) + redis-store (>= 1.1.0, < 2) + redis-activesupport (5.0.4) activesupport (>= 3, < 6) - redis-store (~> 1.3.0) + redis-store (>= 1.3, < 2) redis-namespace (1.5.3) redis (~> 3.0, >= 3.0.4) - redis-rack (2.0.2) + redis-rack (2.0.3) rack (>= 1.5, < 3) - redis-store (>= 1.2, < 1.4) + redis-store (>= 1.2, < 2) redis-rails (5.0.2) redis-actionpack (>= 5.0, < 6) redis-activesupport (>= 5.0, < 6) redis-store (>= 1.2, < 2) - redis-store (1.3.0) - redis (>= 2.2) + redis-store (1.4.1) + redis (>= 2.2, < 5) request_store (1.3.2) responders (2.4.0) actionpack (>= 4.2.0, < 5.3) @@ -411,27 +412,27 @@ GEM rotp (2.1.2) rqrcode (0.10.1) chunky_png (~> 1.0) - rspec-core (3.6.0) - rspec-support (~> 3.6.0) - rspec-expectations (3.6.0) + rspec-core (3.7.0) + rspec-support (~> 3.7.0) + rspec-expectations (3.7.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) - rspec-mocks (3.6.0) + rspec-support (~> 3.7.0) + rspec-mocks (3.7.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) - rspec-rails (3.6.1) + rspec-support (~> 3.7.0) + rspec-rails (3.7.1) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec-core (~> 3.6.0) - rspec-expectations (~> 3.6.0) - rspec-mocks (~> 3.6.0) - rspec-support (~> 3.6.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-support (~> 3.7.0) rspec-sidekiq (3.0.3) rspec-core (~> 3.0, >= 3.0.0) sidekiq (>= 2.4.0) - rspec-support (3.6.0) - rubocop (0.50.0) + rspec-support (3.7.0) + rubocop (0.51.0) parallel (~> 1.10) parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) @@ -439,7 +440,7 @@ GEM ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) ruby-oembed (0.12.0) - ruby-progressbar (1.8.3) + ruby-progressbar (1.9.0) rufus-scheduler (3.4.2) et-orbi (~> 1.0) safe_yaml (1.0.4) @@ -448,19 +449,19 @@ GEM nokogiri (>= 1.4.4) nokogumbo (~> 1.4.1) sass (3.4.25) - scss_lint (0.54.0) + scss_lint (0.55.0) rake (>= 0.9, < 13) sass (~> 3.4.20) - sidekiq (5.0.4) + sidekiq (5.0.5) concurrent-ruby (~> 1.0) connection_pool (~> 2.2, >= 2.2.0) rack-protection (>= 1.5.0) - redis (~> 3.3, >= 3.3.3) + redis (>= 3.3.4, < 5) sidekiq-bulk (0.1.1) activesupport sidekiq - sidekiq-scheduler (2.1.9) - redis (~> 3) + sidekiq-scheduler (2.1.10) + redis (>= 3, < 5) rufus-scheduler (~> 3.2) sidekiq (>= 3) tilt (>= 1.4.0) @@ -477,7 +478,6 @@ GEM json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.2) - slop (3.6.0) sprockets (3.7.1) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -500,9 +500,9 @@ GEM tilt (2.0.8) twitter-text (1.14.7) unf (~> 0.1.0) - tzinfo (1.2.3) + tzinfo (1.2.4) thread_safe (~> 0.1) - tzinfo-data (1.2017.2) + tzinfo-data (1.2017.3) tzinfo (>= 1.0.0) uglifier (3.2.0) execjs (>= 0.3.0, < 3) @@ -517,7 +517,7 @@ GEM addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff - webpacker (3.0.1) + webpacker (3.0.2) activesupport (>= 4.2) rack-proxy (>= 0.6.1) railties (>= 4.2) @@ -539,18 +539,18 @@ DEPENDENCIES addressable (~> 2.5) annotate (~> 2.7) aws-sdk (~> 2.9) - better_errors (~> 2.1) + better_errors (~> 2.4) binding_of_caller (~> 0.7) bootsnap brakeman (~> 4.0) browser bullet (~> 5.5) bundler-audit (~> 0.6) - capistrano (~> 3.8) - capistrano-rails (~> 1.2) + capistrano (~> 3.10) + capistrano-rails (~> 1.3) capistrano-rbenv (~> 2.1) capistrano-yarn (~> 2.0) - capybara (~> 2.14) + capybara (~> 2.15) charlock_holmes (~> 0.7.5) cld3 (~> 3.2.0) climate_control (~> 0.2) @@ -558,7 +558,7 @@ DEPENDENCIES devise-two-factor (~> 3.0) doorkeeper (~> 4.2) dotenv-rails (~> 2.2) - fabrication (~> 2.16) + fabrication (~> 2.18) faker (~> 1.7) fast_blank (~> 1.0) fog-openstack (~> 0.1) @@ -574,22 +574,22 @@ DEPENDENCIES idn-ruby iso-639 json-ld-preloaded (~> 2.2.1) - kaminari (~> 1.0) + kaminari (~> 1.1) letter_opener (~> 1.4) letter_opener_web (~> 1.3) link_header (~> 0.0) - lograge (~> 0.5) + lograge (~> 0.7) mario-redis-lock (~> 1.2) microformats (~> 4.0) mime-types (~> 3.1) - nokogiri (~> 1.7) + nokogiri (~> 1.8) nsa (~> 0.2) - oj (~> 3.0) + oj (~> 3.3) ostatus2 (~> 2.0) - ox (~> 2.5) + ox (~> 2.8) paperclip (~> 5.1) paperclip-av-transcoder (~> 0.6) - parallel_tests (~> 2.14) + parallel_tests (~> 2.17) pg (~> 0.20) pghero (~> 1.7) pkg-config (~> 1.2) @@ -609,12 +609,12 @@ DEPENDENCIES redis-namespace (~> 1.5) redis-rails (~> 5.0) rqrcode (~> 0.10) - rspec-rails (~> 3.6) + rspec-rails (~> 3.7) rspec-sidekiq (~> 3.0) rubocop ruby-oembed (~> 0.12) sanitize (~> 4.4) - scss_lint (~> 0.53) + scss_lint (~> 0.55) sidekiq (~> 5.0) sidekiq-bulk (~> 0.1.1) sidekiq-scheduler (~> 2.1) diff --git a/bin/webpack b/bin/webpack index 528233a78..9d3800c74 100755 --- a/bin/webpack +++ b/bin/webpack @@ -1,27 +1,17 @@ #!/usr/bin/env ruby -$stdout.sync = true +# frozen_string_literal: true +# +# This file was generated by Bundler. +# +# The application 'webpack' is installed as part of a gem, and +# this file is here to facilitate running it. +# -require "shellwords" +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) -ENV["RAILS_ENV"] ||= "development" -RAILS_ENV = ENV["RAILS_ENV"] +require "rubygems" +require "bundler/setup" -ENV["NODE_ENV"] ||= RAILS_ENV -NODE_ENV = ENV["NODE_ENV"] - -APP_PATH = File.expand_path("../", __dir__) -NODE_MODULES_PATH = File.join(APP_PATH, "node_modules") -WEBPACK_CONFIG = File.join(APP_PATH, "config/webpack/#{NODE_ENV}.js") - -unless File.exist?(WEBPACK_CONFIG) - puts "Webpack configuration not found." - puts "Please run bundle exec rails webpacker:install to install webpacker" - exit! -end - -env = { "NODE_PATH" => NODE_MODULES_PATH.shellescape } -cmd = [ "#{NODE_MODULES_PATH}/.bin/webpack", "--config", WEBPACK_CONFIG ] + ARGV - -Dir.chdir(APP_PATH) do - exec env, *cmd -end +load Gem.bin_path("webpacker", "webpack") diff --git a/bin/webpack-dev-server b/bin/webpack-dev-server index c9672f663..cf701102a 100755 --- a/bin/webpack-dev-server +++ b/bin/webpack-dev-server @@ -1,68 +1,17 @@ #!/usr/bin/env ruby -$stdout.sync = true - -require "shellwords" -require "yaml" -require "socket" - -ENV["RAILS_ENV"] ||= "development" -RAILS_ENV = ENV["RAILS_ENV"] - -ENV["NODE_ENV"] ||= RAILS_ENV -NODE_ENV = ENV["NODE_ENV"] - -APP_PATH = File.expand_path("../", __dir__) -CONFIG_FILE = File.join(APP_PATH, "config/webpacker.yml") -NODE_MODULES_PATH = File.join(APP_PATH, "node_modules") -WEBPACK_CONFIG = File.join(APP_PATH, "config/webpack/#{NODE_ENV}.js") - -DEFAULT_LISTEN_HOST_ADDR = NODE_ENV == 'development' ? 'localhost' : '0.0.0.0' - -def args(key) - index = ARGV.index(key) - index ? ARGV[index + 1] : nil -end - -begin - dev_server = YAML.load_file(CONFIG_FILE)[RAILS_ENV]["dev_server"] - - HOSTNAME = args('--host') || dev_server["host"] - PORT = args('--port') || dev_server["port"] - HTTPS = ARGV.include?('--https') || dev_server["https"] - DEV_SERVER_ADDR = "http#{"s" if HTTPS}://#{HOSTNAME}:#{PORT}" - LISTEN_HOST_ADDR = args('--listen-host') || DEFAULT_LISTEN_HOST_ADDR - -rescue Errno::ENOENT, NoMethodError - $stdout.puts "Webpack dev_server configuration not found in #{CONFIG_FILE}." - $stdout.puts "Please run bundle exec rails webpacker:install to install webpacker" - exit! -end - -begin - server = TCPServer.new(LISTEN_HOST_ADDR, PORT) - server.close - -rescue Errno::EADDRINUSE - $stdout.puts "Another program is running on port #{PORT}. Set a new port in #{CONFIG_FILE} for dev_server" - exit! -end - -# Delete supplied host, port and listen-host CLI arguments -["--host", "--port", "--listen-host"].each do |arg| - ARGV.delete(args(arg)) - ARGV.delete(arg) -end - -env = { "NODE_PATH" => NODE_MODULES_PATH.shellescape } - -cmd = [ - "#{NODE_MODULES_PATH}/.bin/webpack-dev-server", "--progress", "--color", - "--config", WEBPACK_CONFIG, - "--host", LISTEN_HOST_ADDR, - "--public", "#{HOSTNAME}:#{PORT}", - "--port", PORT.to_s -] + ARGV - -Dir.chdir(APP_PATH) do - exec env, *cmd -end +# frozen_string_literal: true +# +# This file was generated by Bundler. +# +# The application 'webpack-dev-server' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("webpacker", "webpack-dev-server") diff --git a/config/deploy.rb b/config/deploy.rb index 33b88b109..3fd149f21 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -lock '3.8.2' +lock '3.10.0' set :repo_url, ENV.fetch('REPO', 'https://github.com/tootsuite/mastodon.git') set :branch, ENV.fetch('BRANCH', 'master') -- cgit From 0692991b54c660d1292ff2cea0fa135c952c608e Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Tue, 31 Oct 2017 04:25:51 -0700 Subject: Add ServiceWorker caching for static assets (#5524) --- app/views/home/index.html.haml | 2 -- config/webpack/production.js | 32 +++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'config') diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index 659295ebf..8c88d2d64 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -3,8 +3,6 @@ %link{ href: asset_pack_path('features/compose.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ %link{ href: asset_pack_path('features/home_timeline.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ %link{ href: asset_pack_path('features/notifications.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ - %link{ href: asset_pack_path('features/community_timeline.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ - %link{ href: asset_pack_path('features/public_timeline.js'), crossorigin: 'anonymous', rel: 'preload', as: 'script' }/ %meta{name: 'applicationServerKey', content: Rails.configuration.x.vapid_public_key} %script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json) diff --git a/config/webpack/production.js b/config/webpack/production.js index cd1dd91dc..6de79c811 100644 --- a/config/webpack/production.js +++ b/config/webpack/production.js @@ -48,7 +48,37 @@ module.exports = merge(sharedConfig, { }), new OfflinePlugin({ publicPath: publicPath, // sw.js must be served from the root to avoid scope issues - caches: { }, // do not cache things, we only use it for push notifications for now + caches: { + main: [':rest:'], + additional: [':externals:'], + optional: [ + '**/locale_*.js', // don't fetch every locale; the user only needs one + '**/*_polyfills-*.js', // the user may not need polyfills + '**/*.woff2', // the user may have system-fonts enabled + // images/audio can be cached on-demand + '**/*.png', + '**/*.jpg', + '**/*.jpeg', + '**/*.svg', + '**/*.mp3', + '**/*.ogg', + ], + }, + externals: [ + '/emoji/1f602.svg', // used for emoji picker dropdown + '/emoji/sheet.png', // used in emoji-mart + ], + excludes: [ + '**/*.gz', + '**/*.map', + 'stats.json', + 'report.html', + // any browser that supports ServiceWorker will support woff2 + '**/*.eot', + '**/*.ttf', + '**/*-webfont-*.svg', + '**/*.woff', + ], ServiceWorker: { entry: path.join(__dirname, '../../app/javascript/mastodon/service_worker/entry.js'), cacheName: 'mastodon', -- cgit From 8ae9bd0eea75a0a22c08e1e45b2136674aa88cf5 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Wed, 1 Nov 2017 22:42:19 +0900 Subject: Upgrade compression-webpack-plugin to version 1.0.1 (#5581) --- config/webpack/production.js | 12 +++++++++++- package.json | 5 +++-- yarn.lock | 33 +++++++++++---------------------- 3 files changed, 25 insertions(+), 25 deletions(-) (limited to 'config') diff --git a/config/webpack/production.js b/config/webpack/production.js index 6de79c811..e2d7f11dc 100644 --- a/config/webpack/production.js +++ b/config/webpack/production.js @@ -9,6 +9,16 @@ const OfflinePlugin = require('offline-plugin'); const { publicPath } = require('./configuration.js'); const path = require('path'); +let compressionAlgorithm; +try { + const zopfli = require('node-zopfli'); + compressionAlgorithm = (content, options, fn) => { + zopfli.gzip(content, options, fn); + }; +} catch (error) { + compressionAlgorithm = 'gzip'; +} + module.exports = merge(sharedConfig, { output: { filename: '[name]-[chunkhash].js', @@ -33,7 +43,7 @@ module.exports = merge(sharedConfig, { }), new CompressionPlugin({ asset: '[path].gz[query]', - algorithm: 'gzip', + algorithm: compressionAlgorithm, test: /\.(js|css|html|json|ico|svg|eot|otf|ttf)$/, }), new BundleAnalyzerPlugin({ // generates report.html and stats.json diff --git a/package.json b/package.json index 7e46c44de..41f6f817f 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "babel-preset-env": "^1.6.1", "babel-preset-react": "^6.24.1", "classnames": "^2.2.5", - "compression-webpack-plugin": "^0.4.0", + "compression-webpack-plugin": "^1.0.1", "cross-env": "^5.1.1", "css-loader": "^0.28.4", "detect-passive-events": "^1.0.2", @@ -133,6 +133,7 @@ "yargs": "^8.0.2" }, "optionalDependencies": { - "fsevents": "*" + "fsevents": "*", + "node-zopfli": "^2.0.2" } } diff --git a/yarn.lock b/yarn.lock index 738eae505..c6adb3e31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -277,9 +277,11 @@ async-foreach@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" -async@0.2.x: - version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" +async@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7" + dependencies: + lodash "^4.14.0" async@^1.4.0, async@^1.5.2: version "1.5.2" @@ -1559,14 +1561,12 @@ compressible@~2.0.11: dependencies: mime-db ">= 1.30.0 < 2" -compression-webpack-plugin@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-0.4.0.tgz#811de04215f811ea6a12d4d8aed8457d758f13ac" +compression-webpack-plugin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-1.0.1.tgz#7f0a2af9f642b4f87b5989516a3b9e9b41bb4b3f" dependencies: - async "0.2.x" - webpack-sources "^0.1.0" - optionalDependencies: - node-zopfli "^2.0.0" + async "2.4.1" + webpack-sources "^1.0.1" compression@^1.5.2: version "1.7.1" @@ -4618,7 +4618,7 @@ node-sass@^4.5.2: sass-graph "^2.1.1" stdout-stream "^1.4.0" -node-zopfli@^2.0.0: +node-zopfli@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/node-zopfli/-/node-zopfli-2.0.2.tgz#a7a473ae92aaea85d4c68d45bbf2c944c46116b8" dependencies: @@ -6622,10 +6622,6 @@ source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" -source-list-map@~0.1.7: - version "0.1.8" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" - source-map-resolve@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.3.1.tgz#610f6122a445b8dd51535a2a71b783dfc1248761" @@ -7313,13 +7309,6 @@ webpack-merge@^4.1.0: dependencies: lodash "^4.17.4" -webpack-sources@^0.1.0: - version "0.1.5" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.5.tgz#aa1f3abf0f0d74db7111c40e500b84f966640750" - dependencies: - source-list-map "~0.1.7" - source-map "~0.5.3" - webpack-sources@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf" -- cgit From 38d072446be2321c82f42b6e1cf90891f935725c Mon Sep 17 00:00:00 2001 From: MitarashiDango Date: Wed, 1 Nov 2017 22:46:05 +0900 Subject: add account search condition (instance domain) (#5577) --- app/views/admin/accounts/index.html.haml | 2 +- config/locales/en.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'config') diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml index 1b56a3a31..27a0682d8 100644 --- a/app/views/admin/accounts/index.html.haml +++ b/app/views/admin/accounts/index.html.haml @@ -42,7 +42,7 @@ - if params[key].present? = hidden_field_tag key, params[key] - - %i(username display_name email ip).each do |key| + - %i(username by_domain display_name email ip).each do |key| .input.string.optional = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.accounts.#{key}") diff --git a/config/locales/en.yml b/config/locales/en.yml index 2d821550a..d72ec92d0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -59,6 +59,7 @@ en: destroyed_msg: Moderation note successfully destroyed! accounts: are_you_sure: Are you sure? + by_domain: Domain confirm: Confirm confirmed: Confirmed disable_two_factor_authentication: Disable 2FA -- cgit From da3adc0a73abeb7655d7836f1d7a5cbf64f7762f Mon Sep 17 00:00:00 2001 From: Quenty31 <33203663+Quenty31@users.noreply.github.com> Date: Fri, 3 Nov 2017 09:42:30 +0100 Subject: l10n Occitan (#5586) * Update OC: time format Correction for time format according to: https://opinion.jornalet.com/conselh-linguistic-de-jornalet/blog/2379/la-notacion-oraria-en-occitan Harmonisation words in menu and confirmation windows * Update for unlisted custum emoji + #5577 * correction subjonctiu It's either siasque or siague * Corrections Any : qual que, in two words, else it means "some". And "siasque" with S even if I don't pronounce it at all. * Update oc.json --- app/javascript/mastodon/locales/oc.json | 22 +++++++++++----------- config/locales/devise.oc.yml | 2 +- config/locales/oc.yml | 5 +++++ config/locales/simple_form.oc.yml | 2 +- 4 files changed, 18 insertions(+), 13 deletions(-) (limited to 'config') diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 1e0849d95..d826423b5 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -31,7 +31,7 @@ "column.favourites": "Favorits", "column.follow_requests": "Demandas d’abonament", "column.home": "Acuèlh", - "column.mutes": "Personas en silenci", + "column.mutes": "Personas rescondudas", "column.notifications": "Notificacions", "column.pins": "Tuts penjats", "column.public": "Flux public global", @@ -55,12 +55,12 @@ "confirmation_modal.cancel": "Anullar", "confirmations.block.confirm": "Blocar", "confirmations.block.message": "Sètz segur de voler blocar {name} ?", - "confirmations.delete.confirm": "Suprimir", - "confirmations.delete.message": "Sètz segur de voler suprimir l’estatut ?", + "confirmations.delete.confirm": "Escafar", + "confirmations.delete.message": "Sètz segur de voler escafar l’estatut ?", "confirmations.domain_block.confirm": "Amagar tot lo domeni", "confirmations.domain_block.message": "Sètz segur segur de voler blocar completament {domain} ? De còps cal pas que blocar o rescondre unas personas solament.", - "confirmations.mute.confirm": "Metre en silenci", - "confirmations.mute.message": "Sètz segur de voler metre en silenci {name} ?", + "confirmations.mute.confirm": "Rescondre", + "confirmations.mute.message": "Sètz segur de voler rescondre {name} ?", "confirmations.unfollow.confirm": "Quitar de sègre", "confirmations.unfollow.message": "Volètz vertadièrament quitar de sègre {name} ?", "embed.instructions": "Embarcar aqueste estatut per lo far veire sus un site Internet en copiar lo còdi çai-jos.", @@ -135,7 +135,7 @@ "onboarding.page_five.public_timelines": "Lo flux local mòstra los estatuts publics del monde de vòstra instància, aquí {domain}. Lo flux federat mòstra los estatuts publics de la gent que los de {domain} sègon. Son los fluxes publics, un bon biais de trobar de mond.", "onboarding.page_four.home": "Lo flux d’acuèlh mòstra los estatuts del mond que seguètz.", "onboarding.page_four.notifications": "La colomna de notificacions vos fa veire quand qualqu’un interagís amb vos", - "onboarding.page_one.federation": "Mastodon es un malhum de servidors independents que comunican per bastir un malhum mai larg. Òm los apèla instàncias.", + "onboarding.page_one.federation": "Mastodon es un malhum de servidors independents que comunican per construire un malhum mai larg. Òm los apèla instàncias.", "onboarding.page_one.handle": "Sètz sus {domain}, doncas vòstre identificant complet es {handle}", "onboarding.page_one.welcome": "Benvengut a Mastodon !", "onboarding.page_six.admin": "Vòstre administrator d’instància es {admin}.", @@ -159,11 +159,11 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Mostrar pas dins los fluxes publics", "privacy.unlisted.short": "Pas-listat", - "relative_time.days": "fa {number}j", - "relative_time.hours": "fa {number}h", + "relative_time.days": "fa {number} d", + "relative_time.hours": "fa {number} h", "relative_time.just_now": "ara", - "relative_time.minutes": "fa {number} minutas", - "relative_time.seconds": "fa {number} segondas", + "relative_time.minutes": "fa {number} min", + "relative_time.seconds": "fa {number} s", "reply_indicator.cancel": "Anullar", "report.placeholder": "Comentaris addicionals", "report.submit": "Mandar", @@ -197,7 +197,7 @@ "status.share": "Partejar", "status.show_less": "Tornar plegar", "status.show_more": "Desplegar", - "status.unmute_conversation": "Conversacions amb silenci levat", + "status.unmute_conversation": "Tornar mostrar la conversacion", "status.unpin": "Tirar del perfil", "tabs_bar.compose": "Compausar", "tabs_bar.federated_timeline": "Flux public global", diff --git a/config/locales/devise.oc.yml b/config/locales/devise.oc.yml index 5cccb48ff..266f87373 100644 --- a/config/locales/devise.oc.yml +++ b/config/locales/devise.oc.yml @@ -9,7 +9,7 @@ oc: already_authenticated: Sètz ja connectat. inactive: Vòstre compte es pas encara activat. invalid: Corrièl o senhal invalid. - last_attempt: Vos demòra un ensag abans que vòstre compte siasgue blocat. + last_attempt: Vos demòra un ensag abans que vòstre compte siasque blocat. locked: Vòstre compte es blocat. not_found_in_database: Corrièl o senhal invalid. timeout: Vòstra session s’a acabat. Mercés de vos tornar connectar per contunhar. diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 0d2a8c2f6..8e7602106 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -59,6 +59,7 @@ oc: destroyed_msg: Nòta de moderacion ben suprimida ! accounts: are_you_sure: Sètz segur ? + by_domain: Domeni confirm: Confirmar confirmed: Confirmat disable_two_factor_authentication: Desactivar 2FA @@ -130,11 +131,15 @@ oc: enable: Activar enabled_msg: Aqueste emoji es ben activat image_hint: PNG cap a 50Ko + listed: Listat new: title: Ajustar un nòu emoji personal shortcode: Acorchi shortcode_hint: Almens 2 caractèrs, solament alfanumerics e jonhent bas title: Emojis personals + unlisted: Pas listat + update_failed_msg: Mesa a jorn de l’emoji fracasada + updated_msg: Emoji ben mes a jorn ! upload: Enviar domain_blocks: add_new: N’ajustar un nòu diff --git a/config/locales/simple_form.oc.yml b/config/locales/simple_form.oc.yml index d43c0d7eb..f178d1857 100644 --- a/config/locales/simple_form.oc.yml +++ b/config/locales/simple_form.oc.yml @@ -13,7 +13,7 @@ oc: one: Demòra encara 1 caractèr other: Demòran encara %{count} caractèrs setting_noindex: Aquò es destinat a vòstre perfil public e vòstra pagina d’estatuts - setting_theme: Aquò càmbia lo tèma grafic de Mastodon quand sètz connectat qualque siaque lo periferic. + setting_theme: Aquò càmbia lo tèma grafic de Mastodon quand sètz connectat qual que siasque lo periferic. imports: data: Fichièr CSV exportat d’una autra instància Mastodon sessions: -- cgit From 8a588145d54c9b22ecf67048400f5aeee59372ea Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Sun, 5 Nov 2017 21:07:59 +0900 Subject: Update extract-text-webpack-plugin to version 3.0.2 (#5584) --- config/webpack/shared.js | 33 +++++++++++++++------------------ package.json | 2 +- yarn.lock | 12 ++++++------ 3 files changed, 22 insertions(+), 25 deletions(-) (limited to 'config') diff --git a/config/webpack/shared.js b/config/webpack/shared.js index 5ff267fc5..50fa48175 100644 --- a/config/webpack/shared.js +++ b/config/webpack/shared.js @@ -12,27 +12,24 @@ const localePackPaths = require('./generateLocalePacks'); const extensionGlob = `**/*{${settings.extensions.join(',')}}*`; const entryPath = join(settings.source_path, settings.source_entry_path); const packPaths = sync(join(entryPath, extensionGlob)); -const entryPacks = [...packPaths, ...localePackPaths].filter(path => path !== join(entryPath, 'custom.js')); - -const themePaths = Object.keys(themes).reduce( - (themePaths, name) => { - themePaths[name] = resolve(join(settings.source_path, themes[name])); - return themePaths; - }, {}); module.exports = { entry: Object.assign( - entryPacks.reduce( - (map, entry) => { - const localMap = map; - let namespace = relative(join(entryPath), dirname(entry)); - if (namespace === join('..', '..', '..', 'tmp', 'packs')) { - namespace = ''; // generated by generateLocalePacks.js - } - localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry); - return localMap; - }, {} - ), themePaths + packPaths.reduce((map, entry) => { + const localMap = map; + const namespace = relative(join(entryPath), dirname(entry)); + localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry); + return localMap; + }, {}), + localePackPaths.reduce((map, entry) => { + const localMap = map; + localMap[basename(entry, extname(entry, extname(entry)))] = resolve(entry); + return localMap; + }, {}), + Object.keys(themes).reduce((themePaths, name) => { + themePaths[name] = resolve(join(settings.source_path, themes[name])); + return themePaths; + }, {}) ), output: { diff --git a/package.json b/package.json index 1667f232d..cd088e5c0 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "es6-symbol": "^3.1.1", "escape-html": "^1.0.3", "express": "^4.16.2", - "extract-text-webpack-plugin": "^2.1.2", + "extract-text-webpack-plugin": "^3.0.2", "file-loader": "^0.11.2", "font-awesome": "^4.7.0", "glob": "^7.1.1", diff --git a/yarn.lock b/yarn.lock index 4eae5663a..b7aa18a01 100644 --- a/yarn.lock +++ b/yarn.lock @@ -287,7 +287,7 @@ async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.1.2, async@^2.1.4, async@^2.1.5: +async@^2.1.2, async@^2.1.4, async@^2.1.5, async@^2.4.1: version "2.5.0" resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" dependencies: @@ -2607,12 +2607,12 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -extract-text-webpack-plugin@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-2.1.2.tgz#756ef4efa8155c3681833fbc34da53b941746d6c" +extract-text-webpack-plugin@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz#5f043eaa02f9750a9258b78c0a6e0dc1408fb2f7" dependencies: - async "^2.1.2" - loader-utils "^1.0.2" + async "^2.4.1" + loader-utils "^1.1.0" schema-utils "^0.3.0" webpack-sources "^1.0.1" -- cgit From d48779cf7b9cf69a39ea821c3a5ae79f62e39ceb Mon Sep 17 00:00:00 2001 From: Marcin Mikołajczak Date: Sun, 5 Nov 2017 23:06:54 +0100 Subject: i18n: Improve Polish translation (#5596) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcin Mikołajczak --- config/locales/doorkeeper.pl.yml | 6 +++--- config/locales/pl.yml | 21 +++++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'config') diff --git a/config/locales/doorkeeper.pl.yml b/config/locales/doorkeeper.pl.yml index fa4324e4d..33f133c06 100644 --- a/config/locales/doorkeeper.pl.yml +++ b/config/locales/doorkeeper.pl.yml @@ -59,7 +59,7 @@ pl: error: title: Wystapił błąd new: - able_to: Będzie w stanie + able_to: Uzyska prompt: Aplikacja %{client_name} prosi o dostęp do Twojego konta title: Wymagana jest autoryzacja show: @@ -114,6 +114,6 @@ pl: application: title: Uwierzytelnienie OAuth jest wymagane scopes: - follow: śledzenie, blokowanie, usuwanie blokady, anulowanie śledzenia kont + follow: możliwość śledzenia, blokowania, usuwania blokad, anulowania śledzenia kont read: dostęp do odczytu danych konta - write: publikowanie wpisów w Twoim imieniu + write: możliwość publikowania wpisów w Twoim imieniu diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 0d979225d..b486cd4fc 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -59,6 +59,7 @@ pl: destroyed_msg: Pomyślnie usunięto notatkę moderacyjną! accounts: are_you_sure: Jesteś tego pewien? + by_domain: Domena confirm: Potwierdź confirmed: Potwierdzono disable_two_factor_authentication: Wyłącz uwierzytelnianie dwuetapowe @@ -109,7 +110,7 @@ pl: report: zgłoszeń targeted_reports: Zgłoszenia dotyczące tego użytkownika silence: Wycisz - statuses: Statusy + statuses: Wpisy subscribe: Subskrybuj title: Konta undo_silenced: Cofnij wyciszenie @@ -139,7 +140,7 @@ pl: unlisted: Niewidoczne update_failed_msg: Nie udało się zaktualizować emoji updated_msg: Pomyślnie zaktualizowano emoji - upload: Wyślij + upload: Dodaj domain_blocks: add_new: Dodaj nową created_msg: Blokada domen jest przetwarzana @@ -207,7 +208,7 @@ pl: reported_by: Zgłaszający resolved: Rozwiązane silence_account: Wycisz konto - status: Status + status: Stan suspend_account: Zawieś konto target: Cel title: Zgłoszenia @@ -216,7 +217,7 @@ pl: settings: bootstrap_timeline_accounts: desc_html: Oddzielaj nazwy użytkowników przecinkami. Działa tylko dla niezablokowanych kont w obrębie instancji. Jeżeli puste, zostaną użyte konta administratorów instancji. - title: Domyślne obserwacje nowych użytkowników + title: Domyślnie obserwowani użytkownicy contact_information: email: Służbowy adres e-mail username: Nazwa użytkownika do kontaktu @@ -260,7 +261,7 @@ pl: show: Pokaż zawartość multimedialną title: Media no_media: Bez zawartości multimedialnej - title: Statusy konta + title: Wpisy konta with_media: Z zawartością multimedialną subscriptions: callback_url: URL zwrotny @@ -353,7 +354,7 @@ pl: storage: Urządzenie przechowujące dane followers: domain: Domena - explanation_html: Jeżeli chcesz mieć pewność, kto może przeczytać Twoje statusy, musisz kontrolować, kto śledzi Twój profil. Twoje prywatne statusy są dostarczane na te instancje, na których jesteś śledzony. Możesz sprawdzać, kto Cię śledzi i blokować ich, jeśli nie ufasz właścicielom lub oprogramowaniu danej instancji. + explanation_html: Jeżeli chcesz mieć pewność, kto może przeczytać Twoje wpisy, musisz kontrolować, kto śledzi Twój profil. Twoje prywatne wpisy są dostarczane na te instancje, na których jesteś śledzony. Możesz sprawdzać, kto Cię śledzi i blokować ich, jeśli nie ufasz właścicielom lub oprogramowaniu danej instancji. followers_count: Liczba śledzących lock_link: Zablokuj swoje konto purge: Przestań śledzić @@ -361,7 +362,7 @@ pl: one: W trakcie usuwania śledzących z jednej domeny… other: W trakcie usuwania śledzących z %{count} domen… true_privacy_html: Pamiętaj, że rzeczywista prywatność może zostać uzyskana wyłącznie dzięki szyfrowaniu end-to-end. - unlocked_warning_html: Każdy może Cię śledzić, aby natychmiastowo zobaczyć twoje statusy. %{lock_link} aby móc kontrolować, kto Cię śledzi. + unlocked_warning_html: Każdy może Cię śledzić, aby natychmiastowo zobaczyć twoje wpisy. %{lock_link} aby móc kontrolować, kto Cię śledzi. unlocked_warning_title: Twoje konto nie jest zablokowane generic: changes_saved_msg: Ustawienia zapisane! @@ -382,7 +383,7 @@ pl: landing_strip_signup_html: Jeśli jeszcze go nie masz, możesz stworzyć konto. media_attachments: validations: - images_and_video: Nie możesz załączyć pliku wideo do statusu, który zawiera już zdjęcia + images_and_video: Nie możesz załączyć pliku wideo do wpisu, który zawiera już zdjęcia too_many: Nie możesz załączyć więcej niż 4 plików notification_mailer: digest: @@ -435,7 +436,7 @@ pl: web: Sieć push_notifications: favourite: - title: "%{name} dodał Twój status do ulubionych" + title: "%{name} dodał Twój wpis do ulubionych" follow: title: "%{name} zaczął Cię śledzić" group: @@ -446,7 +447,7 @@ pl: action_favourite: Dodaj do ulubionych title: "%{name} wspomniał o Tobie" reblog: - title: "%{name} podbił Twój status" + title: "%{name} podbił Twój wpis" remote_follow: acct: Podaj swój adres (nazwa@domena), z którego chcesz śledzić missing_resource: Nie udało się znaleźć adresu przekierowania z Twojej domeny -- cgit From 47b0c6185356d4a2533b3ef96e9775a3a82da079 Mon Sep 17 00:00:00 2001 From: Yamagishi Kazutoshi Date: Tue, 7 Nov 2017 22:30:31 +0900 Subject: Unify file upload to using fog (#5604) --- Gemfile | 6 ++- Gemfile.lock | 23 +++++----- config/initializers/paperclip.rb | 92 +++++++++++++++++++++++----------------- 3 files changed, 71 insertions(+), 50 deletions(-) (limited to 'config') diff --git a/Gemfile b/Gemfile index e535372f9..d0b7aaef1 100644 --- a/Gemfile +++ b/Gemfile @@ -14,8 +14,10 @@ gem 'pg', '~> 0.20' gem 'pghero', '~> 1.7' gem 'dotenv-rails', '~> 2.2' -gem 'aws-sdk', '~> 2.9' -gem 'fog-openstack', '~> 0.1' +gem 'fog-aws', '~> 1.4', require: false +gem 'fog-core', '~> 1.45' +gem 'fog-local', '~> 0.4', require: false +gem 'fog-openstack', '~> 0.1', require: false gem 'paperclip', '~> 5.1' gem 'paperclip-av-transcoder', '~> 0.6' diff --git a/Gemfile.lock b/Gemfile.lock index 13ca840bb..f9c69d538 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -57,14 +57,6 @@ GEM encryptor (~> 3.0.0) av (0.9.0) cocaine (~> 0.5.3) - aws-sdk (2.10.73) - aws-sdk-resources (= 2.10.73) - aws-sdk-core (2.10.73) - aws-sigv4 (~> 1.0) - jmespath (~> 1.0) - aws-sdk-resources (2.10.73) - aws-sdk-core (= 2.10.73) - aws-sigv4 (1.0.2) bcrypt (3.1.11) better_errors (2.4.0) coderay (>= 1.0.0) @@ -160,6 +152,11 @@ GEM i18n (~> 0.5) fast_blank (1.0.0) ffi (1.9.18) + fog-aws (1.4.1) + fog-core (~> 1.38) + fog-json (~> 1.0) + fog-xml (~> 0.1) + ipaddress (~> 0.8) fog-core (1.45.0) builder excon (~> 0.58) @@ -167,10 +164,15 @@ GEM fog-json (1.0.2) fog-core (~> 1.0) multi_json (~> 1.10) + fog-local (0.4.0) + fog-core (~> 1.27) fog-openstack (0.1.22) fog-core (>= 1.40) fog-json (>= 1.0) ipaddress (>= 0.8) + fog-xml (0.1.3) + fog-core + nokogiri (>= 1.5.11, < 2.0.0) formatador (0.2.5) fuubar (2.2.0) rspec-core (~> 3.0) @@ -226,7 +228,6 @@ GEM idn-ruby (0.1.0) ipaddress (0.8.3) iso-639 (0.2.8) - jmespath (1.3.1) json (2.1.0) json-ld (2.1.7) multi_json (~> 1.12) @@ -538,7 +539,6 @@ DEPENDENCIES active_record_query_trace (~> 1.5) addressable (~> 2.5) annotate (~> 2.7) - aws-sdk (~> 2.9) better_errors (~> 2.4) binding_of_caller (~> 0.7) bootsnap @@ -561,6 +561,9 @@ DEPENDENCIES fabrication (~> 2.18) faker (~> 1.7) fast_blank (~> 1.0) + fog-aws (~> 1.4) + fog-core (~> 1.45) + fog-local (~> 0.4) fog-openstack (~> 0.1) fuubar (~> 2.2) goldfinger (~> 2.0) diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index 2c82a91db..9e846bf6b 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -7,60 +7,76 @@ Paperclip.interpolates :filename do |attachment, style| [basename(attachment, style), extension(attachment, style)].delete_if(&:blank?).join('.') end -Paperclip::Attachment.default_options[:use_timestamp] = false +Paperclip::Attachment.default_options.merge!( + use_timestamp: false, + path: ':class/:attachment/:id_partition/:style/:filename', + storage: :fog +) if ENV['S3_ENABLED'] == 'true' - Aws.eager_autoload!(services: %w(S3)) + require 'fog/aws' - Paperclip::Attachment.default_options[:storage] = :s3 - Paperclip::Attachment.default_options[:s3_protocol] = ENV.fetch('S3_PROTOCOL') { 'https' } - Paperclip::Attachment.default_options[:url] = ':s3_domain_url' - Paperclip::Attachment.default_options[:s3_host_name] = ENV.fetch('S3_HOSTNAME') { "s3-#{ENV.fetch('S3_REGION')}.amazonaws.com" } - Paperclip::Attachment.default_options[:path] = '/:class/:attachment/:id_partition/:style/:filename' - Paperclip::Attachment.default_options[:s3_headers] = { 'Cache-Control' => 'max-age=315576000' } - Paperclip::Attachment.default_options[:s3_permissions] = ENV.fetch('S3_PERMISSION') { 'public-read' } - Paperclip::Attachment.default_options[:s3_region] = ENV.fetch('S3_REGION') { 'us-east-1' } + s3_protocol = ENV.fetch('S3_PROTOCOL') { 'https' } + s3_hostname = ENV.fetch('S3_HOSTNAME') { "s3-#{ENV['S3_REGION']}.amazonaws.com" } + aws_signature_version = ENV['S3_SIGNATURE_VERSION'] == 's3' ? 2 : ENV['S3_SIGNATURE_VERSION'].to_i + aws_signature_version = 4 if aws_signature_version.zero? - Paperclip::Attachment.default_options[:s3_credentials] = { - bucket: ENV.fetch('S3_BUCKET'), - access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'), - secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY'), - } - - unless ENV['S3_ENDPOINT'].blank? - Paperclip::Attachment.default_options[:s3_options] = { - endpoint: ENV['S3_ENDPOINT'], - signature_version: ENV['S3_SIGNATURE_VERSION'] || 'v4', - force_path_style: true, + Paperclip::Attachment.default_options.merge!( + fog_credentials: { + provider: 'AWS', + aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'], + aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'], + aws_signature_version: aws_signature_version, + region: ENV.fetch('S3_REGION') { 'us-east-1' }, + scheme: s3_protocol, + host: s3_hostname + }, + fog_directory: ENV['S3_BUCKET'], + fog_options: { + acl: ENV.fetch('S3_PERMISSION') { 'public-read' }, + cache_control: 'max-age=315576000', } + ) - Paperclip::Attachment.default_options[:url] = ':s3_path_url' + if ENV.has_key?('S3_ENDPOINT') + Paperclip::Attachment.default_options[:fog_credentials].merge!( + endpoint: ENV['S3_ENDPOINT'], + path_style: true + ) + Paperclip::Attachment.default_options[:fog_host] = "#{s3_protocol}://#{s3_hostname}/#{ENV['S3_BUCKET']}" end - unless ENV['S3_CLOUDFRONT_HOST'].blank? - Paperclip::Attachment.default_options[:url] = ':s3_alias_url' - Paperclip::Attachment.default_options[:s3_host_alias] = ENV['S3_CLOUDFRONT_HOST'] + if ENV.has_key?('S3_CLOUDFRONT_HOST') + Paperclip::Attachment.default_options[:fog_host] = "#{s3_protocol}://#{ENV['S3_CLOUDFRONT_HOST']}" end elsif ENV['SWIFT_ENABLED'] == 'true' + require 'fog/openstack' + Paperclip::Attachment.default_options.merge!( - path: ':class/:attachment/:id_partition/:style/:filename', - storage: :fog, fog_credentials: { provider: 'OpenStack', - openstack_username: ENV.fetch('SWIFT_USERNAME'), - openstack_project_name: ENV.fetch('SWIFT_TENANT'), - openstack_tenant: ENV.fetch('SWIFT_TENANT'), # Some OpenStack-v2 ignores project_name but needs tenant - openstack_api_key: ENV.fetch('SWIFT_PASSWORD'), - openstack_auth_url: ENV.fetch('SWIFT_AUTH_URL'), - openstack_domain_name: ENV['SWIFT_DOMAIN_NAME'] || 'default', + openstack_username: ENV['SWIFT_USERNAME'], + openstack_project_name: ENV['SWIFT_TENANT'], + openstack_tenant: ENV['SWIFT_TENANT'], # Some OpenStack-v2 ignores project_name but needs tenant + openstack_api_key: ENV['SWIFT_PASSWORD'], + openstack_auth_url: ENV['SWIFT_AUTH_URL'], + openstack_domain_name: ENV.fetch('SWIFT_DOMAIN_NAME') { 'default' }, openstack_region: ENV['SWIFT_REGION'], - openstack_cache_ttl: ENV['SWIFT_CACHE_TTL'] || 60, + openstack_cache_ttl: ENV.fetch('SWIFT_CACHE_TTL') { 60 }, }, - fog_directory: ENV.fetch('SWIFT_CONTAINER'), - fog_host: ENV['SWIFT_OBJECT_URL'], + fog_directory: ENV['SWIFT_CONTAINER'], + fog_host: ENV['SWIIFT_OBJECT_URL'], fog_public: true ) else - Paperclip::Attachment.default_options[:path] = (ENV['PAPERCLIP_ROOT_PATH'] || ':rails_root/public/system') + '/:class/:attachment/:id_partition/:style/:filename' - Paperclip::Attachment.default_options[:url] = (ENV['PAPERCLIP_ROOT_URL'] || '/system') + '/:class/:attachment/:id_partition/:style/:filename' + require 'fog/local' + + Paperclip::Attachment.default_options.merge!( + fog_credentials: { + provider: 'Local', + local_root: ENV.fetch('PAPERCLIP_ROOT_PATH') { Rails.root.join('public', 'system') }, + }, + fog_directory: '', + fog_host: ENV.fetch('PAPERCLIP_ROOT_URL') { '/system' } + ) end -- cgit From b6e2e999bd4c603bc36b1234af484184644104e9 Mon Sep 17 00:00:00 2001 From: nullkal Date: Tue, 7 Nov 2017 22:49:32 +0900 Subject: Show the local couterpart of emoji when it exists in /admin/custom_emojis (#5467) * Show the local couterpart of emoji when it exists in admin/custom_emojis * Fix indentation * Fix error * Add class table-action-link to Overwrite link * Make it enable to overwrite emojis * Make Code Climate happy --- app/controllers/admin/custom_emojis_controller.rb | 6 +-- app/helpers/application_helper.rb | 4 ++ app/models/custom_emoji.rb | 2 + .../admin/custom_emojis/_custom_emoji.html.haml | 7 ++- config/brakeman.ignore | 56 +++++++++++----------- config/locales/en.yml | 1 + 6 files changed, 43 insertions(+), 33 deletions(-) (limited to 'config') diff --git a/app/controllers/admin/custom_emojis_controller.rb b/app/controllers/admin/custom_emojis_controller.rb index cbd7abe95..daa1460fb 100644 --- a/app/controllers/admin/custom_emojis_controller.rb +++ b/app/controllers/admin/custom_emojis_controller.rb @@ -5,7 +5,7 @@ module Admin before_action :set_custom_emoji, except: [:index, :new, :create] def index - @custom_emojis = filtered_custom_emojis.page(params[:page]) + @custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page]) end def new @@ -36,9 +36,9 @@ module Admin end def copy - emoji = CustomEmoji.new(domain: nil, shortcode: @custom_emoji.shortcode, image: @custom_emoji.image) + emoji = CustomEmoji.find_or_create_by(domain: nil, shortcode: @custom_emoji.shortcode) - if emoji.save + if emoji.update(image: @custom_emoji.image) flash[:notice] = I18n.t('admin.custom_emojis.copied_msg') else flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg') diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6d625e7db..310e1b1b1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -43,6 +43,10 @@ module ApplicationHelper content_tag(:i, nil, attributes.merge(class: class_names.join(' '))) end + def custom_emoji_tag(custom_emoji) + image_tag(custom_emoji.image.url, class: 'emojione', alt: ":#{custom_emoji.shortcode}:") + end + def opengraph(property, content) tag(:meta, content: content, property: property) end diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 28b6a2b0b..a77b53c98 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -25,6 +25,8 @@ class CustomEmoji < ApplicationRecord :(#{SHORTCODE_RE_FRAGMENT}): (?=[^[:alnum:]:]|$)/x + has_one :local_counterpart, -> { where(domain: nil) }, class_name: 'CustomEmoji', primary_key: :shortcode, foreign_key: :shortcode + has_attached_file :image, styles: { static: { format: 'png', convert_options: '-coalesce -strip' } } validates_attachment :image, content_type: { content_type: 'image/png' }, presence: true, size: { in: 0..50.kilobytes } diff --git a/app/views/admin/custom_emojis/_custom_emoji.html.haml b/app/views/admin/custom_emojis/_custom_emoji.html.haml index 399d13bbd..bab34bc8d 100644 --- a/app/views/admin/custom_emojis/_custom_emoji.html.haml +++ b/app/views/admin/custom_emojis/_custom_emoji.html.haml @@ -1,6 +1,6 @@ %tr %td - = image_tag custom_emoji.image.url, class: 'emojione', alt: ":#{custom_emoji.shortcode}:" + = custom_emoji_tag(custom_emoji) %td %samp= ":#{custom_emoji.shortcode}:" %td @@ -15,7 +15,10 @@ - else = table_link_to 'eye-slash', t('admin.custom_emojis.unlisted'), admin_custom_emoji_path(custom_emoji, custom_emoji: { visible_in_picker: true }), method: :patch - else - = table_link_to 'copy', t('admin.custom_emojis.copy'), copy_admin_custom_emoji_path(custom_emoji, page: params[:page]), method: :post + - if custom_emoji.local_counterpart.present? + = link_to safe_join([custom_emoji_tag(custom_emoji.local_counterpart), t('admin.custom_emojis.overwrite')]), copy_admin_custom_emoji_path(custom_emoji, page: params[:page]), method: :post, class: 'table-action-link' + - else + = table_link_to 'copy', t('admin.custom_emojis.copy'), copy_admin_custom_emoji_path(custom_emoji, page: params[:page]), method: :post %td - if custom_emoji.disabled? = table_link_to 'power-off', t('admin.custom_emojis.enable'), enable_admin_custom_emoji_path(custom_emoji), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } diff --git a/config/brakeman.ignore b/config/brakeman.ignore index f198eebac..f7cf89dff 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -10,7 +10,7 @@ "line": 122, "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).inbox_url, Account.find(params[:id]).inbox_url)", - "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":13,"file":"app/controllers/admin/accounts_controller.rb"}], + "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { "type": "template", "template": "admin/accounts/show" @@ -29,7 +29,7 @@ "line": 128, "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).shared_inbox_url, Account.find(params[:id]).shared_inbox_url)", - "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":13,"file":"app/controllers/admin/accounts_controller.rb"}], + "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { "type": "template", "template": "admin/accounts/show" @@ -48,7 +48,7 @@ "line": 35, "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).url, Account.find(params[:id]).url)", - "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":13,"file":"app/controllers/admin/accounts_controller.rb"}], + "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { "type": "template", "template": "admin/accounts/show" @@ -57,25 +57,6 @@ "confidence": "Weak", "note": "" }, - { - "warning_type": "Dynamic Render Path", - "warning_code": 15, - "fingerprint": "3b0a20b08aef13cf8cf865384fae0cfd3324d8200a83262bf4abbc8091b5fec5", - "check_name": "Render", - "message": "Render path contains parameter value", - "file": "app/views/admin/custom_emojis/index.html.haml", - "line": 31, - "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", - "code": "render(action => filtered_custom_emojis.page(params[:page]), {})", - "render_path": [{"type":"controller","class":"Admin::CustomEmojisController","method":"index","line":9,"file":"app/controllers/admin/custom_emojis_controller.rb"}], - "location": { - "type": "template", - "template": "admin/custom_emojis/index" - }, - "user_input": "params[:page]", - "confidence": "Weak", - "note": "" - }, { "warning_type": "Dynamic Render Path", "warning_code": 15, @@ -105,7 +86,7 @@ "line": 131, "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).followers_url, Account.find(params[:id]).followers_url)", - "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":13,"file":"app/controllers/admin/accounts_controller.rb"}], + "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { "type": "template", "template": "admin/accounts/show" @@ -124,7 +105,7 @@ "line": 106, "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).salmon_url, Account.find(params[:id]).salmon_url)", - "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":13,"file":"app/controllers/admin/accounts_controller.rb"}], + "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { "type": "template", "template": "admin/accounts/show" @@ -133,6 +114,25 @@ "confidence": "Weak", "note": "" }, + { + "warning_type": "Dynamic Render Path", + "warning_code": 15, + "fingerprint": "8d843713d99e8403f7992f3e72251b633817cf9076ffcbbad5613859d2bbc127", + "check_name": "Render", + "message": "Render path contains parameter value", + "file": "app/views/admin/custom_emojis/index.html.haml", + "line": 31, + "link": "http://brakemanscanner.org/docs/warning_types/dynamic_render_path/", + "code": "render(action => filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page]), {})", + "render_path": [{"type":"controller","class":"Admin::CustomEmojisController","method":"index","line":9,"file":"app/controllers/admin/custom_emojis_controller.rb"}], + "location": { + "type": "template", + "template": "admin/custom_emojis/index" + }, + "user_input": "params[:page]", + "confidence": "Weak", + "note": "" + }, { "warning_type": "SQL Injection", "warning_code": 0, @@ -140,7 +140,7 @@ "check_name": "SQL", "message": "Possible SQL injection", "file": "lib/mastodon/snowflake.rb", - "line": 86, + "line": 87, "link": "http://brakemanscanner.org/docs/warning_types/sql_injection/", "code": "connection.execute(\" CREATE OR REPLACE FUNCTION timestamp_id(table_name text)\\n RETURNS bigint AS\\n $$\\n DECLARE\\n time_part bigint;\\n sequence_base bigint;\\n tail bigint;\\n BEGIN\\n time_part := (\\n -- Get the time in milliseconds\\n ((date_part('epoch', now()) * 1000))::bigint\\n -- And shift it over two bytes\\n << 16);\\n\\n sequence_base := (\\n 'x' ||\\n -- Take the first two bytes (four hex characters)\\n substr(\\n -- Of the MD5 hash of the data we documented\\n md5(table_name ||\\n '#{SecureRandom.hex(16)}' ||\\n time_part::text\\n ),\\n 1, 4\\n )\\n -- And turn it into a bigint\\n )::bit(16)::bigint;\\n\\n -- Finally, add our sequence number to our base, and chop\\n -- it to the last two bytes\\n tail := (\\n (sequence_base + nextval(table_name || '_id_seq'))\\n & 65535);\\n\\n -- Return the time part and the sequence part. OR appears\\n -- faster here than addition, but they're equivalent:\\n -- time_part has no trailing two bytes, and tail is only\\n -- the last two bytes.\\n RETURN time_part | tail;\\n END\\n $$ LANGUAGE plpgsql VOLATILE;\\n\")", "render_path": null, @@ -182,7 +182,7 @@ "line": 95, "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).remote_url, Account.find(params[:id]).remote_url)", - "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":13,"file":"app/controllers/admin/accounts_controller.rb"}], + "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { "type": "template", "template": "admin/accounts/show" @@ -240,7 +240,7 @@ "line": 125, "link": "http://brakemanscanner.org/docs/warning_types/link_to_href", "code": "link_to(Account.find(params[:id]).outbox_url, Account.find(params[:id]).outbox_url)", - "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":13,"file":"app/controllers/admin/accounts_controller.rb"}], + "render_path": [{"type":"controller","class":"Admin::AccountsController","method":"show","line":15,"file":"app/controllers/admin/accounts_controller.rb"}], "location": { "type": "template", "template": "admin/accounts/show" @@ -269,6 +269,6 @@ "note": "" } ], - "updated": "2017-10-07 19:24:02 +0200", + "updated": "2017-10-20 00:00:54 +0900", "brakeman_version": "4.0.1" } diff --git a/config/locales/en.yml b/config/locales/en.yml index d72ec92d0..ce439029c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -134,6 +134,7 @@ en: listed: Listed new: title: Add new custom emoji + overwrite: Overwrite shortcode: Shortcode shortcode_hint: At least 2 characters, only alphanumeric characters and underscores title: Custom emojis -- cgit From cbbeec05be5cd0930a7be73bf673acc8d8105c12 Mon Sep 17 00:00:00 2001 From: MitarashiDango Date: Wed, 8 Nov 2017 03:06:30 +0900 Subject: Fix spell miss (SWIIFT_OBJECT_URL -> SWIFT_OBJECT_URL) (#5617) --- config/initializers/paperclip.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config') diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index 9e846bf6b..14bd034e6 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -65,7 +65,7 @@ elsif ENV['SWIFT_ENABLED'] == 'true' openstack_cache_ttl: ENV.fetch('SWIFT_CACHE_TTL') { 60 }, }, fog_directory: ENV['SWIFT_CONTAINER'], - fog_host: ENV['SWIIFT_OBJECT_URL'], + fog_host: ENV['SWIFT_OBJECT_URL'], fog_public: true ) else -- cgit From 1032f3994fdbd61c2f517057261ddc3559199b6b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 7 Nov 2017 19:06:44 +0100 Subject: Add ability to disable login and mark accounts as memorial (#5615) Fix #5597 --- app/controllers/admin/accounts_controller.rb | 22 ++++++++++++++- app/controllers/admin/suspensions_controller.rb | 2 +- app/javascript/styles/mastodon/landing_strip.scss | 7 ++++- app/mailers/notification_mailer.rb | 18 ++++++++---- app/mailers/user_mailer.rb | 6 ++++ app/models/account.rb | 15 ++++++++++ app/models/user.rb | 18 +++++++++++- app/services/suspend_account_service.rb | 25 +++++++++------- app/views/accounts/_header.html.haml | 33 +++++++++++----------- app/views/accounts/show.html.haml | 4 ++- app/views/admin/accounts/show.html.haml | 11 ++++++++ app/workers/admin/suspension_worker.rb | 2 +- config/locales/en.yml | 7 +++++ config/routes.rb | 3 ++ .../20171107143332_add_memorial_to_accounts.rb | 15 ++++++++++ db/migrate/20171107143624_add_disabled_to_users.rb | 15 ++++++++++ db/schema.rb | 4 ++- 17 files changed, 168 insertions(+), 39 deletions(-) create mode 100644 db/migrate/20171107143332_add_memorial_to_accounts.rb create mode 100644 db/migrate/20171107143624_add_disabled_to_users.rb (limited to 'config') diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index ffa4dc850..7503b880d 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -2,8 +2,9 @@ module Admin class AccountsController < BaseController - before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload] + before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :enable, :disable, :memorialize] before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload] + before_action :require_local_account!, only: [:enable, :disable, :memorialize] def index @accounts = filtered_accounts.page(params[:page]) @@ -24,6 +25,21 @@ module Admin redirect_to admin_account_path(@account.id) end + def memorialize + @account.memorialize! + redirect_to admin_account_path(@account.id) + end + + def enable + @account.user.enable! + redirect_to admin_account_path(@account.id) + end + + def disable + @account.user.disable! + redirect_to admin_account_path(@account.id) + end + def redownload @account.reset_avatar! @account.reset_header! @@ -42,6 +58,10 @@ module Admin redirect_to admin_account_path(@account.id) if @account.local? end + def require_local_account! + redirect_to admin_account_path(@account.id) unless @account.local? && @account.user.present? + end + def filtered_accounts AccountFilter.new(filter_params).results end diff --git a/app/controllers/admin/suspensions_controller.rb b/app/controllers/admin/suspensions_controller.rb index 5d9048d94..5eaf1a2e9 100644 --- a/app/controllers/admin/suspensions_controller.rb +++ b/app/controllers/admin/suspensions_controller.rb @@ -10,7 +10,7 @@ module Admin end def destroy - @account.update(suspended: false) + @account.unsuspend! redirect_to admin_accounts_path end diff --git a/app/javascript/styles/mastodon/landing_strip.scss b/app/javascript/styles/mastodon/landing_strip.scss index 15ff84912..0bf9daafd 100644 --- a/app/javascript/styles/mastodon/landing_strip.scss +++ b/app/javascript/styles/mastodon/landing_strip.scss @@ -1,4 +1,5 @@ -.landing-strip { +.landing-strip, +.memoriam-strip { background: rgba(darken($ui-base-color, 7%), 0.8); color: $ui-primary-color; font-weight: 400; @@ -29,3 +30,7 @@ margin-bottom: 0; } } + +.memoriam-strip { + background: rgba($base-shadow-color, 0.7); +} diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb index 80c9d8ccf..d79f26366 100644 --- a/app/mailers/notification_mailer.rb +++ b/app/mailers/notification_mailer.rb @@ -7,6 +7,8 @@ class NotificationMailer < ApplicationMailer @me = recipient @status = notification.target_status + return if @me.user.disabled? + locale_for_account(@me) do thread_by_conversation(@status.conversation) mail to: @me.user.email, subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct) @@ -17,6 +19,8 @@ class NotificationMailer < ApplicationMailer @me = recipient @account = notification.from_account + return if @me.user.disabled? + locale_for_account(@me) do mail to: @me.user.email, subject: I18n.t('notification_mailer.follow.subject', name: @account.acct) end @@ -27,6 +31,8 @@ class NotificationMailer < ApplicationMailer @account = notification.from_account @status = notification.target_status + return if @me.user.disabled? + locale_for_account(@me) do thread_by_conversation(@status.conversation) mail to: @me.user.email, subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct) @@ -38,6 +44,8 @@ class NotificationMailer < ApplicationMailer @account = notification.from_account @status = notification.target_status + return if @me.user.disabled? + locale_for_account(@me) do thread_by_conversation(@status.conversation) mail to: @me.user.email, subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct) @@ -48,6 +56,8 @@ class NotificationMailer < ApplicationMailer @me = recipient @account = notification.from_account + return if @me.user.disabled? + locale_for_account(@me) do mail to: @me.user.email, subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct) end @@ -59,15 +69,11 @@ class NotificationMailer < ApplicationMailer @notifications = Notification.where(account: @me, activity_type: 'Mention').where('created_at > ?', @since) @follows_since = Notification.where(account: @me, activity_type: 'Follow').where('created_at > ?', @since).count - return if @notifications.empty? + return if @me.user.disabled? || @notifications.empty? locale_for_account(@me) do mail to: @me.user.email, - subject: I18n.t( - :subject, - scope: [:notification_mailer, :digest], - count: @notifications.size - ) + subject: I18n.t(:subject, scope: [:notification_mailer, :digest], count: @notifications.size) end end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index c475a9911..bdb29ebad 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -10,6 +10,8 @@ class UserMailer < Devise::Mailer @token = token @instance = Rails.configuration.x.local_domain + return if @resource.disabled? + I18n.with_locale(@resource.locale || I18n.default_locale) do mail to: @resource.unconfirmed_email.blank? ? @resource.email : @resource.unconfirmed_email, subject: I18n.t('devise.mailer.confirmation_instructions.subject', instance: @instance) end @@ -20,6 +22,8 @@ class UserMailer < Devise::Mailer @token = token @instance = Rails.configuration.x.local_domain + return if @resource.disabled? + I18n.with_locale(@resource.locale || I18n.default_locale) do mail to: @resource.email, subject: I18n.t('devise.mailer.reset_password_instructions.subject') end @@ -29,6 +33,8 @@ class UserMailer < Devise::Mailer @resource = user @instance = Rails.configuration.x.local_domain + return if @resource.disabled? + I18n.with_locale(@resource.locale || I18n.default_locale) do mail to: @resource.email, subject: I18n.t('devise.mailer.password_change.subject') end diff --git a/app/models/account.rb b/app/models/account.rb index 3dc2a95ab..1142e7c79 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -41,6 +41,7 @@ # shared_inbox_url :string default(""), not null # followers_url :string default(""), not null # protocol :integer default("ostatus"), not null +# memorial :boolean default(FALSE), not null # class Account < ApplicationRecord @@ -150,6 +151,20 @@ class Account < ApplicationRecord ResolveRemoteAccountService.new.call(acct) end + def unsuspend! + transaction do + user&.enable! if local? + update!(suspended: false) + end + end + + def memorialize! + transaction do + user&.disable! if local? + update!(memorial: true) + end + end + def keypair @keypair ||= OpenSSL::PKey::RSA.new(private_key || public_key) end diff --git a/app/models/user.rb b/app/models/user.rb index 325e27f44..836d54d15 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,7 +5,6 @@ # # id :integer not null, primary key # email :string default(""), not null -# account_id :integer not null # created_at :datetime not null # updated_at :datetime not null # encrypted_password :string default(""), not null @@ -31,10 +30,13 @@ # last_emailed_at :datetime # otp_backup_codes :string is an Array # filtered_languages :string default([]), not null, is an Array +# account_id :integer not null +# disabled :boolean default(FALSE), not null # class User < ApplicationRecord include Settings::Extend + ACTIVE_DURATION = 14.days devise :registerable, :recoverable, @@ -72,12 +74,26 @@ class User < ApplicationRecord confirmed_at.present? end + def disable! + update!(disabled: true, + last_sign_in_at: current_sign_in_at, + current_sign_in_at: nil) + end + + def enable! + update!(disabled: false) + end + def disable_two_factor! self.otp_required_for_login = false otp_backup_codes&.clear save! end + def active_for_authentication? + super && !disabled? + end + def setting_default_privacy settings.default_privacy || (account.locked? ? 'private' : 'public') end diff --git a/app/services/suspend_account_service.rb b/app/services/suspend_account_service.rb index 983c5495b..5b37ba9ba 100644 --- a/app/services/suspend_account_service.rb +++ b/app/services/suspend_account_service.rb @@ -1,22 +1,27 @@ # frozen_string_literal: true class SuspendAccountService < BaseService - def call(account, remove_user = false) + def call(account, options = {}) @account = account + @options = options - purge_user if remove_user - purge_profile - purge_content - unsubscribe_push_subscribers + purge_user! + purge_profile! + purge_content! + unsubscribe_push_subscribers! end private - def purge_user - @account.user.destroy + def purge_user! + if @options[:remove_user] + @account.user&.destroy + else + @account.user&.disable! + end end - def purge_content + def purge_content! @account.statuses.reorder(nil).find_in_batches do |statuses| BatchedRemoveStatusService.new.call(statuses) end @@ -33,7 +38,7 @@ class SuspendAccountService < BaseService end end - def purge_profile + def purge_profile! @account.suspended = true @account.display_name = '' @account.note = '' @@ -42,7 +47,7 @@ class SuspendAccountService < BaseService @account.save! end - def unsubscribe_push_subscribers + def unsubscribe_push_subscribers! destroy_all(@account.subscriptions) end diff --git a/app/views/accounts/_header.html.haml b/app/views/accounts/_header.html.haml index 08c3891d2..5530fcc20 100644 --- a/app/views/accounts/_header.html.haml +++ b/app/views/accounts/_header.html.haml @@ -1,21 +1,22 @@ .card.h-card.p-author{ style: "background-image: url(#{account.header.url(:original)})" } .card__illustration - - if user_signed_in? && current_account.id != account.id && !current_account.requested?(account) - .controls - - if current_account.following?(account) - = link_to account_unfollow_path(account), data: { method: :post }, class: 'icon-button' do - = fa_icon 'user-times' - = t('accounts.unfollow') - - else - = link_to account_follow_path(account), data: { method: :post }, class: 'icon-button' do - = fa_icon 'user-plus' - = t('accounts.follow') - - elsif !user_signed_in? - .controls - .remote-follow - = link_to account_remote_follow_path(account), class: 'icon-button' do - = fa_icon 'user-plus' - = t('accounts.remote_follow') + - unless account.memorial? + - if user_signed_in? && current_account.id != account.id && !current_account.requested?(account) + .controls + - if current_account.following?(account) + = link_to account_unfollow_path(account), data: { method: :post }, class: 'icon-button' do + = fa_icon 'user-times' + = t('accounts.unfollow') + - else + = link_to account_follow_path(account), data: { method: :post }, class: 'icon-button' do + = fa_icon 'user-plus' + = t('accounts.follow') + - elsif !user_signed_in? + .controls + .remote-follow + = link_to account_remote_follow_path(account), class: 'icon-button' do + = fa_icon 'user-plus' + = t('accounts.remote_follow') .avatar= image_tag account.avatar.url(:original), class: 'u-photo' diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml index 6c90b2c04..fd8ad5530 100644 --- a/app/views/accounts/show.html.haml +++ b/app/views/accounts/show.html.haml @@ -12,7 +12,9 @@ = opengraph 'og:type', 'profile' = render 'og', account: @account, url: short_account_url(@account, only_path: false) -- if show_landing_strip? +- if @account.memorial? + .memoriam-strip= t('in_memoriam_html') +- elsif show_landing_strip? = render partial: 'shared/landing_strip', locals: { account: @account } .h-feed diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index 1f5c8fcf5..b5ce56dbc 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -18,6 +18,15 @@ %tr %th= t('admin.accounts.email') %td= @account.user_email + %tr + %th= t('admin.accounts.login_status') + %td + - if @account.user&.disabled? + = t('admin.accounts.disabled') + = table_link_to 'unlock', t('admin.accounts.enable'), enable_admin_account_path(@account.id), method: :post + - else + = t('admin.accounts.enabled') + = table_link_to 'lock', t('admin.accounts.disable'), disable_admin_account_path(@account.id), method: :post %tr %th= t('admin.accounts.most_recent_ip') %td= @account.user_current_sign_in_ip @@ -65,6 +74,8 @@ = link_to t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, class: 'button' - if @account.user&.otp_required_for_login? = link_to t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete, class: 'button' + - unless @account.memorial? + = link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' - else = link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' diff --git a/app/workers/admin/suspension_worker.rb b/app/workers/admin/suspension_worker.rb index 6338b1130..e41465ccc 100644 --- a/app/workers/admin/suspension_worker.rb +++ b/app/workers/admin/suspension_worker.rb @@ -6,6 +6,6 @@ class Admin::SuspensionWorker sidekiq_options queue: 'pull' def perform(account_id, remove_user = false) - SuspendAccountService.new.call(Account.find(account_id), remove_user) + SuspendAccountService.new.call(Account.find(account_id), remove_user: remove_user) end end diff --git a/config/locales/en.yml b/config/locales/en.yml index ce439029c..41a636760 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -62,11 +62,15 @@ en: by_domain: Domain confirm: Confirm confirmed: Confirmed + disable: Disable disable_two_factor_authentication: Disable 2FA + disabled: Disabled display_name: Display name domain: Domain edit: Edit email: E-mail + enable: Enable + enabled: Enabled feed_url: Feed URL followers: Followers followers_url: Followers URL @@ -78,7 +82,9 @@ en: local: Local remote: Remote title: Location + login_status: Login status media_attachments: Media attachments + memorialize: Turn into memoriam moderation: all: All silenced: Silenced @@ -379,6 +385,7 @@ en: following: Following list muting: Muting list upload: Upload + in_memoriam_html: In Memoriam. landing_strip_html: "%{name} is a user on %{link_to_root_path}. You can follow them or interact with them if you have an account anywhere in the fediverse." landing_strip_signup_html: If you don't, you can sign up here. media_attachments: diff --git a/config/routes.rb b/config/routes.rb index bdfcdaff6..e6d6b52f7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -126,7 +126,10 @@ Rails.application.routes.draw do member do post :subscribe post :unsubscribe + post :enable + post :disable post :redownload + post :memorialize end resource :reset, only: [:create] diff --git a/db/migrate/20171107143332_add_memorial_to_accounts.rb b/db/migrate/20171107143332_add_memorial_to_accounts.rb new file mode 100644 index 000000000..f3e012ce8 --- /dev/null +++ b/db/migrate/20171107143332_add_memorial_to_accounts.rb @@ -0,0 +1,15 @@ +require Rails.root.join('lib', 'mastodon', 'migration_helpers') + +class AddMemorialToAccounts < ActiveRecord::Migration[5.1] + include Mastodon::MigrationHelpers + + disable_ddl_transaction! + + def up + safety_assured { add_column_with_default :accounts, :memorial, :bool, default: false } + end + + def down + remove_column :accounts, :memorial + end +end diff --git a/db/migrate/20171107143624_add_disabled_to_users.rb b/db/migrate/20171107143624_add_disabled_to_users.rb new file mode 100644 index 000000000..a71cac1c6 --- /dev/null +++ b/db/migrate/20171107143624_add_disabled_to_users.rb @@ -0,0 +1,15 @@ +require Rails.root.join('lib', 'mastodon', 'migration_helpers') + +class AddDisabledToUsers < ActiveRecord::Migration[5.1] + include Mastodon::MigrationHelpers + + disable_ddl_transaction! + + def up + safety_assured { add_column_with_default :users, :disabled, :bool, default: false } + end + + def down + remove_column :users, :disabled + end +end diff --git a/db/schema.rb b/db/schema.rb index 697a7f374..935fd79c5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20171020084748) do +ActiveRecord::Schema.define(version: 20171107143624) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -71,6 +71,7 @@ ActiveRecord::Schema.define(version: 20171020084748) do t.string "shared_inbox_url", default: "", null: false t.string "followers_url", default: "", null: false t.integer "protocol", default: 0, null: false + t.boolean "memorial", default: false, null: false t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower" t.index ["uri"], name: "index_accounts_on_uri" @@ -435,6 +436,7 @@ ActiveRecord::Schema.define(version: 20171020084748) do t.string "otp_backup_codes", array: true t.string "filtered_languages", default: [], null: false, array: true t.bigint "account_id", null: false + t.boolean "disabled", default: false, null: false t.index ["account_id"], name: "index_users_on_account_id" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true -- cgit From eb97bd8af6c9a06a52cc8b12d05ac9ea1aa5370a Mon Sep 17 00:00:00 2001 From: Quenty31 <33203663+Quenty31@users.noreply.github.com> Date: Wed, 8 Nov 2017 15:19:49 +0100 Subject: i10n OC: Memorial (#5615) + #5467 (#5623) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Changed ĩ => ï * Changed ĩ => ï * Add ability to disable login and mark accounts as memorial (#5615) --- app/views/user_mailer/reset_password_instructions.oc.html.erb | 2 +- app/views/user_mailer/reset_password_instructions.oc.text.erb | 2 +- config/locales/oc.yml | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'config') diff --git a/app/views/user_mailer/reset_password_instructions.oc.html.erb b/app/views/user_mailer/reset_password_instructions.oc.html.erb index 6c775b3a1..92e4b8f8b 100644 --- a/app/views/user_mailer/reset_password_instructions.oc.html.erb +++ b/app/views/user_mailer/reset_password_instructions.oc.html.erb @@ -1,6 +1,6 @@

Bonjorn <%= @resource.email %> !

-

Qualqu’un a demandat la reĩnicializacion de vòstre senhal per Mastodon. Podètz realizar la reĩnicializacion en clicant sul ligam çai-jos.

+

Qualqu’un a demandat la reïnicializacion de vòstre senhal per Mastodon. Podètz realizar la reïnicializacion en clicant sul ligam çai-jos.

<%= link_to 'Modificar mon senhal', edit_password_url(@resource, reset_password_token: @token) %>

diff --git a/app/views/user_mailer/reset_password_instructions.oc.text.erb b/app/views/user_mailer/reset_password_instructions.oc.text.erb index 26432d2df..5a5219589 100644 --- a/app/views/user_mailer/reset_password_instructions.oc.text.erb +++ b/app/views/user_mailer/reset_password_instructions.oc.text.erb @@ -1,6 +1,6 @@ Bonjorn <%= @resource.email %> ! -Qualqu’un a demandat la reĩnicializacion de vòstre senhal per Mastodon. Podètz realizar la reĩnicializacion en clicant sul ligam çai-jos.

+Qualqu’un a demandat la reïnicializacion de vòstre senhal per Mastodon. Podètz realizar la reïnicializacion en clicant sul ligam çai-jos.

<%= link_to 'Modificar mon senhal', edit_password_url(@resource, reset_password_token: @token) %> diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 8e7602106..914cc7e9d 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -62,11 +62,15 @@ oc: by_domain: Domeni confirm: Confirmar confirmed: Confirmat + disable: Desactivar disable_two_factor_authentication: Desactivar 2FA + disabled: Desactivat display_name: Escais-nom domain: Domeni edit: Modificar email: Corrièl + enable: Activar + enabled: Activat feed_url: Flux URL followers: Seguidors followers_url: URL dels seguidors @@ -78,7 +82,9 @@ oc: local: Locals remote: Alonhats title: Emplaçament + login_status: Estat formulari de connexion media_attachments: Mèdias ajustats + memorialize: Passar en memorial moderation: all: Tot silenced: Rescondut @@ -134,6 +140,7 @@ oc: listed: Listat new: title: Ajustar un nòu emoji personal + overwrite: Remplaçar shortcode: Acorchi shortcode_hint: Almens 2 caractèrs, solament alfanumerics e jonhent bas title: Emojis personals @@ -456,6 +463,7 @@ oc: following: Lista de mond que seguètz muting: Lista de mond que volètz pas legir upload: Importar + in_memoriam_html: En Memòria. landing_strip_html: "%{name} utiliza %{link_to_root_path}. Podètz lo/la sègre o interagir amb el o ela s’avètz un compte ont que siasque sul fediverse." landing_strip_signup_html: S’es pas lo cas, podètz vos marcar aquí. media_attachments: -- cgit From 36376b5e230e7df255d6cb6ed22dcca927752156 Mon Sep 17 00:00:00 2001 From: nullkal Date: Thu, 9 Nov 2017 22:22:55 +0900 Subject: Translate ja (#5637) --- config/locales/ja.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'config') diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 391556040..0cb7d9c04 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -59,13 +59,18 @@ ja: destroyed_msg: モデレーションメモを削除しました accounts: are_you_sure: 本当に実行しますか? + by_domain: ドメイン confirm: 確認 confirmed: 確認済み + disable: 無効化 disable_two_factor_authentication: 二段階認証を無効にする + disabled: 無効 display_name: 表示名 domain: ドメイン edit: 編集 email: E-mail + enable: 有効化 + enabled: 有効 feed_url: フィードURL followers: フォロワー数 followers_url: Followers URL @@ -77,7 +82,9 @@ ja: local: ローカル remote: リモート title: ロケーション + login_status: ログイン media_attachments: 添付されたメディア + memorialize: 追悼アカウント化 moderation: all: すべて silenced: サイレンス中 @@ -130,11 +137,16 @@ ja: enable: 有効化 enabled_msg: 絵文字を有効化しました image_hint: 50KBまでのPNG画像を利用できます。 + listed: 収載 new: title: 新規カスタム絵文字の追加 + overwrite: 上書き shortcode: ショートコード shortcode_hint: 2文字以上の半角英数字とアンダーバーのみ利用できます。 title: カスタム絵文字 + unlisted: 未収載 + update_failed_msg: 絵文字を更新できませんでした + updated_msg: 絵文字の更新に成功しました upload: アップロード domain_blocks: add_new: 新規追加 @@ -373,6 +385,7 @@ ja: following: フォロー中のアカウントリスト muting: ミュートしたアカウントリスト upload: アップロード + in_memoriam_html: 故人を偲んで landing_strip_html: "%{name} さんはインスタンス %{link_to_root_path} のユーザーです。アカウントさえ持っていればフォローしたり会話したりできます。" landing_strip_signup_html: もしお持ちでないなら こちら からサインアップできます。 media_attachments: -- cgit From cfd7b7a0b7f97a822cb80de8cbd4e33a07065cc7 Mon Sep 17 00:00:00 2001 From: Marcin Mikołajczak Date: Thu, 9 Nov 2017 14:23:06 +0100 Subject: i18n: Update Polish translation (#5639) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcin Mikołajczak --- config/locales/pl.yml | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'config') diff --git a/config/locales/pl.yml b/config/locales/pl.yml index b486cd4fc..28eee764d 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -62,11 +62,15 @@ pl: by_domain: Domena confirm: Potwierdź confirmed: Potwierdzono + disable: Dezaktywuj disable_two_factor_authentication: Wyłącz uwierzytelnianie dwuetapowe + disabled: Dezaktywowano display_name: Wyświetlana nazwa domain: Domena edit: Edytuj email: Adres e-mail + enable: Aktywuj + enabled: Aktywowano feed_url: Adres kanału followers: Śledzący followers_url: Adres śledzących @@ -78,7 +82,9 @@ pl: local: Lokalne remote: Zdalne title: Położenie + login_status: Stan logowania media_attachments: Załączniki multimedialne + memorialize: Przełącz na „In Memoriam” moderation: all: Wszystkie silenced: Wyciszone @@ -379,6 +385,7 @@ pl: following: Lista śledzonych muting: Lista wyciszonych upload: Załaduj + in_memoriam_html: Ku pamięci. landing_strip_html: "%{name} ma konto na %{link_to_root_path}. Możesz je śledzić i wejść z nim w interakcję jeśli masz konto gdziekolwiek w Fediwersum." landing_strip_signup_html: Jeśli jeszcze go nie masz, możesz stworzyć konto. media_attachments: -- cgit From e5aa4128f62834c94450a311fc6fef9e717c9afc Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 10 Nov 2017 14:58:33 +1300 Subject: Update en.yml (#5648) Changed "Toots with replies" to read "Toots and replies" --- config/locales/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config') diff --git a/config/locales/en.yml b/config/locales/en.yml index 41a636760..be0431ed3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -43,7 +43,7 @@ en: people_followed_by: People whom %{name} follows people_who_follow: People who follow %{name} posts: Toots - posts_with_replies: Toots with replies + posts_with_replies: Toots and replies remote_follow: Remote follow reserved_username: The username is reserved roles: -- cgit From 7bb8b0b2fc0e2e42a4234fed18198cbb7439fe9f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 11 Nov 2017 20:23:33 +0100 Subject: Add moderator role and add pundit policies for admin actions (#5635) * Add moderator role and add pundit policies for admin actions * Add rake task for turning user into mod and revoking it again * Fix handling of unauthorized exception * Deliver new report e-mails to staff, not just admins * Add promote/demote to admin UI, hide some actions conditionally * Fix unused i18n --- .../admin/account_moderation_notes_controller.rb | 56 +++++++++++++--------- app/controllers/admin/accounts_controller.rb | 9 ++++ app/controllers/admin/base_controller.rb | 4 +- app/controllers/admin/confirmations_controller.rb | 9 ++-- app/controllers/admin/custom_emojis_controller.rb | 11 +++++ app/controllers/admin/domain_blocks_controller.rb | 9 +++- .../admin/email_domain_blocks_controller.rb | 5 ++ app/controllers/admin/instances_controller.rb | 2 + .../admin/reported_statuses_controller.rb | 9 ++-- app/controllers/admin/reports_controller.rb | 3 ++ app/controllers/admin/resets_controller.rb | 9 ++-- app/controllers/admin/roles_controller.rb | 25 ++++++++++ app/controllers/admin/settings_controller.rb | 3 ++ app/controllers/admin/silences_controller.rb | 2 + app/controllers/admin/statuses_controller.rb | 17 ++++--- app/controllers/admin/subscriptions_controller.rb | 1 + app/controllers/admin/suspensions_controller.rb | 2 + .../admin/two_factor_authentications_controller.rb | 1 + app/controllers/api/v1/reports_controller.rb | 2 +- app/controllers/application_controller.rb | 5 ++ app/controllers/concerns/authorization.rb | 1 + app/helpers/application_helper.rb | 5 ++ app/models/user.rb | 42 +++++++++++++++- app/policies/account_moderation_note_policy.rb | 17 +++++++ app/policies/account_policy.rb | 43 +++++++++++++++++ app/policies/application_policy.rb | 18 +++++++ app/policies/custom_emoji_policy.rb | 31 ++++++++++++ app/policies/domain_block_policy.rb | 19 ++++++++ app/policies/email_domain_block_policy.rb | 15 ++++++ app/policies/instance_policy.rb | 11 +++++ app/policies/report_policy.rb | 15 ++++++ app/policies/settings_policy.rb | 11 +++++ app/policies/status_policy.rb | 35 +++++++------- app/policies/subscription_policy.rb | 7 +++ app/policies/user_policy.rb | 41 ++++++++++++++++ .../_account_moderation_note.html.haml | 2 +- app/views/admin/accounts/show.html.haml | 46 ++++++++++++------ config/i18n-tasks.yml | 2 + config/locales/en.yml | 7 +++ config/navigation.rb | 16 +++---- config/routes.rb | 7 +++ .../20171109012327_add_moderator_to_accounts.rb | 15 ++++++ db/schema.rb | 3 +- lib/tasks/mastodon.rake | 31 +++++++++++- 44 files changed, 536 insertions(+), 88 deletions(-) create mode 100644 app/controllers/admin/roles_controller.rb create mode 100644 app/policies/account_moderation_note_policy.rb create mode 100644 app/policies/account_policy.rb create mode 100644 app/policies/application_policy.rb create mode 100644 app/policies/custom_emoji_policy.rb create mode 100644 app/policies/domain_block_policy.rb create mode 100644 app/policies/email_domain_block_policy.rb create mode 100644 app/policies/instance_policy.rb create mode 100644 app/policies/report_policy.rb create mode 100644 app/policies/settings_policy.rb create mode 100644 app/policies/subscription_policy.rb create mode 100644 app/policies/user_policy.rb create mode 100644 db/migrate/20171109012327_add_moderator_to_accounts.rb (limited to 'config') diff --git a/app/controllers/admin/account_moderation_notes_controller.rb b/app/controllers/admin/account_moderation_notes_controller.rb index 414a875d0..7f69a3363 100644 --- a/app/controllers/admin/account_moderation_notes_controller.rb +++ b/app/controllers/admin/account_moderation_notes_controller.rb @@ -1,31 +1,41 @@ # frozen_string_literal: true -class Admin::AccountModerationNotesController < Admin::BaseController - def create - @account_moderation_note = current_account.account_moderation_notes.new(resource_params) - if @account_moderation_note.save - @target_account = @account_moderation_note.target_account - redirect_to admin_account_path(@target_account.id), notice: I18n.t('admin.account_moderation_notes.created_msg') - else - @account = @account_moderation_note.target_account - @moderation_notes = @account.targeted_moderation_notes.latest - render template: 'admin/accounts/show' +module Admin + class AccountModerationNotesController < BaseController + before_action :set_account_moderation_note, only: [:destroy] + + def create + authorize AccountModerationNote, :create? + + @account_moderation_note = current_account.account_moderation_notes.new(resource_params) + + if @account_moderation_note.save + redirect_to admin_account_path(@account_moderation_note.target_account_id), notice: I18n.t('admin.account_moderation_notes.created_msg') + else + @account = @account_moderation_note.target_account + @moderation_notes = @account.targeted_moderation_notes.latest + + render template: 'admin/accounts/show' + end end - end - def destroy - @account_moderation_note = AccountModerationNote.find(params[:id]) - @target_account = @account_moderation_note.target_account - @account_moderation_note.destroy - redirect_to admin_account_path(@target_account.id), notice: I18n.t('admin.account_moderation_notes.destroyed_msg') - end + def destroy + authorize @account_moderation_note, :destroy? + @account_moderation_note.destroy + redirect_to admin_account_path(@account_moderation_note.target_account_id), notice: I18n.t('admin.account_moderation_notes.destroyed_msg') + end - private + private - def resource_params - params.require(:account_moderation_note).permit( - :content, - :target_account_id - ) + def resource_params + params.require(:account_moderation_note).permit( + :content, + :target_account_id + ) + end + + def set_account_moderation_note + @account_moderation_note = AccountModerationNote.find(params[:id]) + end end end diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index 7503b880d..0829bc769 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -7,40 +7,49 @@ module Admin before_action :require_local_account!, only: [:enable, :disable, :memorialize] def index + authorize :account, :index? @accounts = filtered_accounts.page(params[:page]) end def show + authorize @account, :show? @account_moderation_note = current_account.account_moderation_notes.new(target_account: @account) @moderation_notes = @account.targeted_moderation_notes.latest end def subscribe + authorize @account, :subscribe? Pubsubhubbub::SubscribeWorker.perform_async(@account.id) redirect_to admin_account_path(@account.id) end def unsubscribe + authorize @account, :unsubscribe? Pubsubhubbub::UnsubscribeWorker.perform_async(@account.id) redirect_to admin_account_path(@account.id) end def memorialize + authorize @account, :memorialize? @account.memorialize! redirect_to admin_account_path(@account.id) end def enable + authorize @account.user, :enable? @account.user.enable! redirect_to admin_account_path(@account.id) end def disable + authorize @account.user, :disable? @account.user.disable! redirect_to admin_account_path(@account.id) end def redownload + authorize @account, :redownload? + @account.reset_avatar! @account.reset_header! @account.save! diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 11fe326bc..db4839a8f 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -2,7 +2,9 @@ module Admin class BaseController < ApplicationController - before_action :require_admin! + include Authorization + + before_action :require_staff! layout 'admin' end diff --git a/app/controllers/admin/confirmations_controller.rb b/app/controllers/admin/confirmations_controller.rb index 2542e21ee..c10b0ebee 100644 --- a/app/controllers/admin/confirmations_controller.rb +++ b/app/controllers/admin/confirmations_controller.rb @@ -2,15 +2,18 @@ module Admin class ConfirmationsController < BaseController + before_action :set_user + def create - account_user.confirm + authorize @user, :confirm? + @user.confirm! redirect_to admin_accounts_path end private - def account_user - Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) + def set_user + @user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) end end end diff --git a/app/controllers/admin/custom_emojis_controller.rb b/app/controllers/admin/custom_emojis_controller.rb index daa1460fb..693d28b1f 100644 --- a/app/controllers/admin/custom_emojis_controller.rb +++ b/app/controllers/admin/custom_emojis_controller.rb @@ -5,14 +5,18 @@ module Admin before_action :set_custom_emoji, except: [:index, :new, :create] def index + authorize :custom_emoji, :index? @custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page]) end def new + authorize :custom_emoji, :create? @custom_emoji = CustomEmoji.new end def create + authorize :custom_emoji, :create? + @custom_emoji = CustomEmoji.new(resource_params) if @custom_emoji.save @@ -23,6 +27,8 @@ module Admin end def update + authorize @custom_emoji, :update? + if @custom_emoji.update(resource_params) redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.updated_msg') else @@ -31,11 +37,14 @@ module Admin end def destroy + authorize @custom_emoji, :destroy? @custom_emoji.destroy redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.destroyed_msg') end def copy + authorize @custom_emoji, :copy? + emoji = CustomEmoji.find_or_create_by(domain: nil, shortcode: @custom_emoji.shortcode) if emoji.update(image: @custom_emoji.image) @@ -48,11 +57,13 @@ module Admin end def enable + authorize @custom_emoji, :enable? @custom_emoji.update!(disabled: false) redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.enabled_msg') end def disable + authorize @custom_emoji, :disable? @custom_emoji.update!(disabled: true) redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.disabled_msg') end diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb index 1ab620e03..e383dc831 100644 --- a/app/controllers/admin/domain_blocks_controller.rb +++ b/app/controllers/admin/domain_blocks_controller.rb @@ -5,14 +5,18 @@ module Admin before_action :set_domain_block, only: [:show, :destroy] def index + authorize :domain_block, :index? @domain_blocks = DomainBlock.page(params[:page]) end def new + authorize :domain_block, :create? @domain_block = DomainBlock.new end def create + authorize :domain_block, :create? + @domain_block = DomainBlock.new(resource_params) if @domain_block.save @@ -23,9 +27,12 @@ module Admin end end - def show; end + def show + authorize @domain_block, :show? + end def destroy + authorize @domain_block, :destroy? UnblockDomainService.new.call(@domain_block, retroactive_unblock?) redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.destroyed_msg') end diff --git a/app/controllers/admin/email_domain_blocks_controller.rb b/app/controllers/admin/email_domain_blocks_controller.rb index 09275d5dc..01058bf46 100644 --- a/app/controllers/admin/email_domain_blocks_controller.rb +++ b/app/controllers/admin/email_domain_blocks_controller.rb @@ -5,14 +5,18 @@ module Admin before_action :set_email_domain_block, only: [:show, :destroy] def index + authorize :email_domain_block, :index? @email_domain_blocks = EmailDomainBlock.page(params[:page]) end def new + authorize :email_domain_block, :create? @email_domain_block = EmailDomainBlock.new end def create + authorize :email_domain_block, :create? + @email_domain_block = EmailDomainBlock.new(resource_params) if @email_domain_block.save @@ -23,6 +27,7 @@ module Admin end def destroy + authorize @email_domain_block, :destroy? @email_domain_block.destroy redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.destroyed_msg') end diff --git a/app/controllers/admin/instances_controller.rb b/app/controllers/admin/instances_controller.rb index 22f02e5d0..8ed0ea421 100644 --- a/app/controllers/admin/instances_controller.rb +++ b/app/controllers/admin/instances_controller.rb @@ -3,10 +3,12 @@ module Admin class InstancesController < BaseController def index + authorize :instance, :index? @instances = ordered_instances end def resubscribe + authorize :instance, :resubscribe? params.require(:by_domain) Pubsubhubbub::SubscribeWorker.push_bulk(subscribeable_accounts.pluck(:id)) redirect_to admin_instances_path diff --git a/app/controllers/admin/reported_statuses_controller.rb b/app/controllers/admin/reported_statuses_controller.rb index 5a31adecf..4f66ce708 100644 --- a/app/controllers/admin/reported_statuses_controller.rb +++ b/app/controllers/admin/reported_statuses_controller.rb @@ -2,19 +2,20 @@ module Admin class ReportedStatusesController < BaseController - include Authorization - before_action :set_report before_action :set_status, only: [:update, :destroy] def create - @form = Form::StatusBatch.new(form_status_batch_params) - flash[:alert] = t('admin.statuses.failed_to_execute') unless @form.save + authorize :status, :update? + + @form = Form::StatusBatch.new(form_status_batch_params) + flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save redirect_to admin_report_path(@report) end def update + authorize @status, :update? @status.update(status_params) redirect_to admin_report_path(@report) end diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb index 226467739..745757ee8 100644 --- a/app/controllers/admin/reports_controller.rb +++ b/app/controllers/admin/reports_controller.rb @@ -5,14 +5,17 @@ module Admin before_action :set_report, except: [:index] def index + authorize :report, :index? @reports = filtered_reports.page(params[:page]) end def show + authorize @report, :show? @form = Form::StatusBatch.new end def update + authorize @report, :update? process_report redirect_to admin_report_path(@report) end diff --git a/app/controllers/admin/resets_controller.rb b/app/controllers/admin/resets_controller.rb index 6db648403..00b590bf6 100644 --- a/app/controllers/admin/resets_controller.rb +++ b/app/controllers/admin/resets_controller.rb @@ -2,17 +2,18 @@ module Admin class ResetsController < BaseController - before_action :set_account + before_action :set_user def create - @account.user.send_reset_password_instructions + authorize @user, :reset_password? + @user.send_reset_password_instructions redirect_to admin_accounts_path end private - def set_account - @account = Account.find(params[:account_id]) + def set_user + @user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) end end end diff --git a/app/controllers/admin/roles_controller.rb b/app/controllers/admin/roles_controller.rb new file mode 100644 index 000000000..8f8685827 --- /dev/null +++ b/app/controllers/admin/roles_controller.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Admin + class RolesController < BaseController + before_action :set_user + + def promote + authorize @user, :promote? + @user.promote! + redirect_to admin_account_path(@user.account_id) + end + + def demote + authorize @user, :demote? + @user.demote! + redirect_to admin_account_path(@user.account_id) + end + + private + + def set_user + @user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) + end + end +end diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb index a2f86b8a9..e81290228 100644 --- a/app/controllers/admin/settings_controller.rb +++ b/app/controllers/admin/settings_controller.rb @@ -28,10 +28,13 @@ module Admin ).freeze def edit + authorize :settings, :show? @admin_settings = Form::AdminSettings.new end def update + authorize :settings, :update? + settings_params.each do |key, value| if UPLOAD_SETTINGS.include?(key) upload = SiteUpload.where(var: key).first_or_initialize(var: key) diff --git a/app/controllers/admin/silences_controller.rb b/app/controllers/admin/silences_controller.rb index 81a3008b9..01fb292de 100644 --- a/app/controllers/admin/silences_controller.rb +++ b/app/controllers/admin/silences_controller.rb @@ -5,11 +5,13 @@ module Admin before_action :set_account def create + authorize @account, :silence? @account.update(silenced: true) redirect_to admin_accounts_path end def destroy + authorize @account, :unsilence? @account.update(silenced: false) redirect_to admin_accounts_path end diff --git a/app/controllers/admin/statuses_controller.rb b/app/controllers/admin/statuses_controller.rb index b05000b16..b54a9b824 100644 --- a/app/controllers/admin/statuses_controller.rb +++ b/app/controllers/admin/statuses_controller.rb @@ -2,8 +2,6 @@ module Admin class StatusesController < BaseController - include Authorization - helper_method :current_params before_action :set_account @@ -12,24 +10,30 @@ module Admin PER_PAGE = 20 def index + authorize :status, :index? + @statuses = @account.statuses + if params[:media] account_media_status_ids = @account.media_attachments.attached.reorder(nil).select(:status_id).distinct @statuses.merge!(Status.where(id: account_media_status_ids)) end - @statuses = @statuses.preload(:media_attachments, :mentions).page(params[:page]).per(PER_PAGE) - @form = Form::StatusBatch.new + @statuses = @statuses.preload(:media_attachments, :mentions).page(params[:page]).per(PER_PAGE) + @form = Form::StatusBatch.new end def create - @form = Form::StatusBatch.new(form_status_batch_params) - flash[:alert] = t('admin.statuses.failed_to_execute') unless @form.save + authorize :status, :update? + + @form = Form::StatusBatch.new(form_status_batch_params) + flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save redirect_to admin_account_statuses_path(@account.id, current_params) end def update + authorize @status, :update? @status.update(status_params) redirect_to admin_account_statuses_path(@account.id, current_params) end @@ -60,6 +64,7 @@ module Admin def current_params page = (params[:page] || 1).to_i + { media: params[:media], page: page > 1 && page, diff --git a/app/controllers/admin/subscriptions_controller.rb b/app/controllers/admin/subscriptions_controller.rb index 624a475a3..40500ef43 100644 --- a/app/controllers/admin/subscriptions_controller.rb +++ b/app/controllers/admin/subscriptions_controller.rb @@ -3,6 +3,7 @@ module Admin class SubscriptionsController < BaseController def index + authorize :subscription, :index? @subscriptions = ordered_subscriptions.page(requested_page) end diff --git a/app/controllers/admin/suspensions_controller.rb b/app/controllers/admin/suspensions_controller.rb index 5eaf1a2e9..778feea5e 100644 --- a/app/controllers/admin/suspensions_controller.rb +++ b/app/controllers/admin/suspensions_controller.rb @@ -5,11 +5,13 @@ module Admin before_action :set_account def create + authorize @account, :suspend? Admin::SuspensionWorker.perform_async(@account.id) redirect_to admin_accounts_path end def destroy + authorize @account, :unsuspend? @account.unsuspend! redirect_to admin_accounts_path end diff --git a/app/controllers/admin/two_factor_authentications_controller.rb b/app/controllers/admin/two_factor_authentications_controller.rb index 69c08f605..5a45d25cd 100644 --- a/app/controllers/admin/two_factor_authentications_controller.rb +++ b/app/controllers/admin/two_factor_authentications_controller.rb @@ -5,6 +5,7 @@ module Admin before_action :set_user def destroy + authorize @user, :disable_2fa? @user.disable_two_factor! redirect_to admin_accounts_path end diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index 9592cd4bd..22828217d 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -19,7 +19,7 @@ class Api::V1::ReportsController < Api::BaseController comment: report_params[:comment] ) - User.admins.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later } + User.staff.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later } render json: @report, serializer: REST::ReportSerializer end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d5eca6ffb..f41a7f9be 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -18,6 +18,7 @@ class ApplicationController < ActionController::Base rescue_from ActionController::RoutingError, with: :not_found rescue_from ActiveRecord::RecordNotFound, with: :not_found rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity + rescue_from Mastodon::NotPermittedError, with: :forbidden before_action :store_current_location, except: :raise_not_found, unless: :devise_controller? before_action :check_suspension, if: :user_signed_in? @@ -40,6 +41,10 @@ class ApplicationController < ActionController::Base redirect_to root_path unless current_user&.admin? end + def require_staff! + redirect_to root_path unless current_user&.staff? + end + def check_suspension forbidden if current_user.account.suspended? end diff --git a/app/controllers/concerns/authorization.rb b/app/controllers/concerns/authorization.rb index 7828fe48d..95a37e379 100644 --- a/app/controllers/concerns/authorization.rb +++ b/app/controllers/concerns/authorization.rb @@ -2,6 +2,7 @@ module Authorization extend ActiveSupport::Concern + include Pundit def pundit_user diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 310e1b1b1..7dfab1df1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -35,6 +35,11 @@ module ApplicationHelper Rails.env.production? ? site_title : "#{site_title} (Dev)" end + def can?(action, record) + return false if record.nil? + policy(record).public_send("#{action}?") + end + def fa_icon(icon, attributes = {}) class_names = attributes[:class]&.split(' ') || [] class_names << 'fa' diff --git a/app/models/user.rb b/app/models/user.rb index 836d54d15..9022e6ea8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -32,6 +32,7 @@ # filtered_languages :string default([]), not null, is an Array # account_id :integer not null # disabled :boolean default(FALSE), not null +# moderator :boolean default(FALSE), not null # class User < ApplicationRecord @@ -53,8 +54,10 @@ class User < ApplicationRecord validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale? validates_with BlacklistedEmailValidator, if: :email_changed? - scope :recent, -> { order(id: :desc) } - scope :admins, -> { where(admin: true) } + scope :recent, -> { order(id: :desc) } + scope :admins, -> { where(admin: true) } + scope :moderators, -> { where(moderator: true) } + scope :staff, -> { admins.or(moderators) } scope :confirmed, -> { where.not(confirmed_at: nil) } scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) } scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended: false }) } @@ -74,6 +77,20 @@ class User < ApplicationRecord confirmed_at.present? end + def staff? + admin? || moderator? + end + + def role + if admin? + 'admin' + elsif moderator? + 'moderator' + else + 'user' + end + end + def disable! update!(disabled: true, last_sign_in_at: current_sign_in_at, @@ -84,6 +101,27 @@ class User < ApplicationRecord update!(disabled: false) end + def confirm! + skip_confirmation! + save! + end + + def promote! + if moderator? + update!(moderator: false, admin: true) + elsif !admin? + update!(moderator: true) + end + end + + def demote! + if admin? + update!(admin: false, moderator: true) + elsif moderator? + update!(moderator: false) + end + end + def disable_two_factor! self.otp_required_for_login = false otp_backup_codes&.clear diff --git a/app/policies/account_moderation_note_policy.rb b/app/policies/account_moderation_note_policy.rb new file mode 100644 index 000000000..885411a5b --- /dev/null +++ b/app/policies/account_moderation_note_policy.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AccountModerationNotePolicy < ApplicationPolicy + def create? + staff? + end + + def destroy? + admin? || owner? + end + + private + + def owner? + record.account_id == current_account&.id + end +end diff --git a/app/policies/account_policy.rb b/app/policies/account_policy.rb new file mode 100644 index 000000000..85e2c8419 --- /dev/null +++ b/app/policies/account_policy.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +class AccountPolicy < ApplicationPolicy + def index? + staff? + end + + def show? + staff? + end + + def suspend? + staff? && !record.user&.staff? + end + + def unsuspend? + staff? + end + + def silence? + staff? && !record.user&.staff? + end + + def unsilence? + staff? + end + + def redownload? + admin? + end + + def subscribe? + admin? + end + + def unsubscribe? + admin? + end + + def memorialize? + admin? && !record.user&.admin? + end +end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb new file mode 100644 index 000000000..3e617001f --- /dev/null +++ b/app/policies/application_policy.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class ApplicationPolicy + attr_reader :current_account, :record + + def initialize(current_account, record) + @current_account = current_account + @record = record + end + + delegate :admin?, :moderator?, :staff?, to: :current_user, allow_nil: true + + private + + def current_user + current_account&.user + end +end diff --git a/app/policies/custom_emoji_policy.rb b/app/policies/custom_emoji_policy.rb new file mode 100644 index 000000000..a8c3cbc73 --- /dev/null +++ b/app/policies/custom_emoji_policy.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class CustomEmojiPolicy < ApplicationPolicy + def index? + staff? + end + + def create? + admin? + end + + def update? + admin? + end + + def copy? + admin? + end + + def enable? + staff? + end + + def disable? + staff? + end + + def destroy? + admin? + end +end diff --git a/app/policies/domain_block_policy.rb b/app/policies/domain_block_policy.rb new file mode 100644 index 000000000..47c0a81af --- /dev/null +++ b/app/policies/domain_block_policy.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class DomainBlockPolicy < ApplicationPolicy + def index? + admin? + end + + def show? + admin? + end + + def create? + admin? + end + + def destroy? + admin? + end +end diff --git a/app/policies/email_domain_block_policy.rb b/app/policies/email_domain_block_policy.rb new file mode 100644 index 000000000..5a75ee183 --- /dev/null +++ b/app/policies/email_domain_block_policy.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class EmailDomainBlockPolicy < ApplicationPolicy + def index? + admin? + end + + def create? + admin? + end + + def destroy? + admin? + end +end diff --git a/app/policies/instance_policy.rb b/app/policies/instance_policy.rb new file mode 100644 index 000000000..d1956e2de --- /dev/null +++ b/app/policies/instance_policy.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class InstancePolicy < ApplicationPolicy + def index? + admin? + end + + def resubscribe? + admin? + end +end diff --git a/app/policies/report_policy.rb b/app/policies/report_policy.rb new file mode 100644 index 000000000..95b5c30c8 --- /dev/null +++ b/app/policies/report_policy.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class ReportPolicy < ApplicationPolicy + def update? + staff? + end + + def index? + staff? + end + + def show? + staff? + end +end diff --git a/app/policies/settings_policy.rb b/app/policies/settings_policy.rb new file mode 100644 index 000000000..2dcb79f51 --- /dev/null +++ b/app/policies/settings_policy.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class SettingsPolicy < ApplicationPolicy + def update? + admin? + end + + def show? + admin? + end +end diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb index 2ded61850..0373fdf04 100644 --- a/app/policies/status_policy.rb +++ b/app/policies/status_policy.rb @@ -1,20 +1,17 @@ # frozen_string_literal: true -class StatusPolicy - attr_reader :account, :status - - def initialize(account, status) - @account = account - @status = status +class StatusPolicy < ApplicationPolicy + def index? + staff? end def show? if direct? - owned? || status.mentions.where(account: account).exists? + owned? || record.mentions.where(account: current_account).exists? elsif private? - owned? || account&.following?(status.account) || status.mentions.where(account: account).exists? + owned? || current_account&.following?(author) || record.mentions.where(account: current_account).exists? else - account.nil? || !status.account.blocking?(account) + current_account.nil? || !author.blocking?(current_account) end end @@ -23,26 +20,30 @@ class StatusPolicy end def destroy? - admin? || owned? + staff? || owned? end alias unreblog? destroy? - private - - def admin? - account&.user&.admin? + def update? + staff? end + private + def direct? - status.direct_visibility? + record.direct_visibility? end def owned? - status.account.id == account&.id + author.id == current_account&.id end def private? - status.private_visibility? + record.private_visibility? + end + + def author + record.account end end diff --git a/app/policies/subscription_policy.rb b/app/policies/subscription_policy.rb new file mode 100644 index 000000000..ac9a8a6c4 --- /dev/null +++ b/app/policies/subscription_policy.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class SubscriptionPolicy < ApplicationPolicy + def index? + admin? + end +end diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb new file mode 100644 index 000000000..aae207d06 --- /dev/null +++ b/app/policies/user_policy.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +class UserPolicy < ApplicationPolicy + def reset_password? + staff? && !record.staff? + end + + def disable_2fa? + admin? && !record.staff? + end + + def confirm? + staff? && !record.confirmed? + end + + def enable? + admin? + end + + def disable? + admin? && !record.admin? + end + + def promote? + admin? && promoteable? + end + + def demote? + admin? && !record.admin? && demoteable? + end + + private + + def promoteable? + !record.staff? || !record.admin? + end + + def demoteable? + record.staff? + end +end diff --git a/app/views/admin/account_moderation_notes/_account_moderation_note.html.haml b/app/views/admin/account_moderation_notes/_account_moderation_note.html.haml index 4651630e9..6761a4319 100644 --- a/app/views/admin/account_moderation_notes/_account_moderation_note.html.haml +++ b/app/views/admin/account_moderation_notes/_account_moderation_note.html.haml @@ -7,4 +7,4 @@ %time.formatted{ datetime: account_moderation_note.created_at.iso8601, title: l(account_moderation_note.created_at) } = l account_moderation_note.created_at %td - = link_to t('admin.account_moderation_notes.delete'), admin_account_moderation_note_path(account_moderation_note), method: :delete + = link_to t('admin.account_moderation_notes.delete'), admin_account_moderation_note_path(account_moderation_note), method: :delete if can?(:destroy, account_moderation_note) diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml index b5ce56dbc..f49594828 100644 --- a/app/views/admin/accounts/show.html.haml +++ b/app/views/admin/accounts/show.html.haml @@ -17,16 +17,20 @@ - if @account.local? %tr %th= t('admin.accounts.email') - %td= @account.user_email + %td + = @account.user_email + + - if @account.user_confirmed? + = fa_icon('check') %tr %th= t('admin.accounts.login_status') %td - if @account.user&.disabled? = t('admin.accounts.disabled') - = table_link_to 'unlock', t('admin.accounts.enable'), enable_admin_account_path(@account.id), method: :post + = table_link_to 'unlock', t('admin.accounts.enable'), enable_admin_account_path(@account.id), method: :post if can?(:enable, @account.user) - else = t('admin.accounts.enabled') - = table_link_to 'lock', t('admin.accounts.disable'), disable_admin_account_path(@account.id), method: :post + = table_link_to 'lock', t('admin.accounts.disable'), disable_admin_account_path(@account.id), method: :post if can?(:disable, @account.user) %tr %th= t('admin.accounts.most_recent_ip') %td= @account.user_current_sign_in_ip @@ -71,28 +75,28 @@ %div{ style: 'overflow: hidden' } %div{ style: 'float: right' } - if @account.local? - = link_to t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, class: 'button' + = link_to t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, class: 'button' if can?(:reset_password, @account.user) - if @account.user&.otp_required_for_login? - = link_to t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete, class: 'button' + = link_to t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete, class: 'button' if can?(:disable_2fa, @account.user) - unless @account.memorial? - = link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' + = link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:memorialize, @account) - else - = link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' + = link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' if can?(:redownload, @account) %div{ style: 'float: left' } - if @account.silenced? - = link_to t('admin.accounts.undo_silenced'), admin_account_silence_path(@account.id), method: :delete, class: 'button' + = link_to t('admin.accounts.undo_silenced'), admin_account_silence_path(@account.id), method: :delete, class: 'button' if can?(:unsilence, @account) - else - = link_to t('admin.accounts.silence'), admin_account_silence_path(@account.id), method: :post, class: 'button' + = link_to t('admin.accounts.silence'), admin_account_silence_path(@account.id), method: :post, class: 'button' if can?(:silence, @account) - if @account.local? - unless @account.user_confirmed? - = link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button' + = link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button' if can?(:confirm, @account.user) - if @account.suspended? - = link_to t('admin.accounts.undo_suspension'), admin_account_suspension_path(@account.id), method: :delete, class: 'button' + = link_to t('admin.accounts.undo_suspension'), admin_account_suspension_path(@account.id), method: :delete, class: 'button' if can?(:unsuspend, @account) - else - = link_to t('admin.accounts.perform_full_suspension'), admin_account_suspension_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' + = link_to t('admin.accounts.perform_full_suspension'), admin_account_suspension_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:suspend, @account) - unless @account.local? %hr @@ -118,9 +122,9 @@ %div{ style: 'overflow: hidden' } %div{ style: 'float: right' } - = link_to @account.subscribed? ? t('admin.accounts.resubscribe') : t('admin.accounts.subscribe'), subscribe_admin_account_path(@account.id), method: :post, class: 'button' + = link_to @account.subscribed? ? t('admin.accounts.resubscribe') : t('admin.accounts.subscribe'), subscribe_admin_account_path(@account.id), method: :post, class: 'button' if can?(:subscribe, @account) - if @account.subscribed? - = link_to t('admin.accounts.unsubscribe'), unsubscribe_admin_account_path(@account.id), method: :post, class: 'button negative' + = link_to t('admin.accounts.unsubscribe'), unsubscribe_admin_account_path(@account.id), method: :post, class: 'button negative' if can?(:unsubscribe, @account) %hr %h3 ActivityPub @@ -141,6 +145,20 @@ %th= t('admin.accounts.followers_url') %td= link_to @account.followers_url, @account.followers_url +- else + %hr + + .table-wrapper + %table.table + %tbody + %tr + %th= t('admin.accounts.role') + %td + = t("admin.accounts.roles.#{@account.user&.role}") + %td< + = table_link_to 'angle-double-up', t('admin.accounts.promote'), promote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:promote, @account.user) + = table_link_to 'angle-double-down', t('admin.accounts.demote'), demote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:demote, @account.user) + %hr %h3= t('admin.accounts.moderation_notes') diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index b35e5c09a..08a96f727 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -46,6 +46,7 @@ ignore_missing: - 'terms.body_html' - 'application_mailer.salutation' - 'errors.500' + ignore_unused: - 'activemodel.errors.*' - 'activerecord.attributes.*' @@ -58,3 +59,4 @@ ignore_unused: - 'errors.messages.*' - 'activerecord.errors.models.doorkeeper/*' - 'errors.429' + - 'admin.accounts.roles.*' diff --git a/config/locales/en.yml b/config/locales/en.yml index be0431ed3..e94165317 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -62,6 +62,7 @@ en: by_domain: Domain confirm: Confirm confirmed: Confirmed + demote: Demote disable: Disable disable_two_factor_authentication: Disable 2FA disabled: Disabled @@ -101,6 +102,7 @@ en: outbox_url: Outbox URL perform_full_suspension: Perform full suspension profile_url: Profile URL + promote: Promote protocol: Protocol public: Public push_subscription_expires: PuSH subscription expires @@ -108,6 +110,11 @@ en: reset: Reset reset_password: Reset password resubscribe: Resubscribe + role: Permissions + roles: + admin: Administrator + moderator: Moderator + user: User salmon_url: Salmon URL search: Search shared_inbox_url: Shared Inbox URL diff --git a/config/navigation.rb b/config/navigation.rb index 50bfbd480..5b4800f07 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -20,16 +20,16 @@ SimpleNavigation::Configuration.run do |navigation| development.item :your_apps, safe_join([fa_icon('list fw'), t('settings.your_apps')]), settings_applications_url, highlights_on: %r{/settings/applications} end - primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_reports_url, if: proc { current_user.admin? } do |admin| + primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_reports_url, if: proc { current_user.staff? } do |admin| admin.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports} admin.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts} - admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url, highlights_on: %r{/admin/instances} - admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url - admin.item :domain_blocks, safe_join([fa_icon('lock fw'), t('admin.domain_blocks.title')]), admin_domain_blocks_url, highlights_on: %r{/admin/domain_blocks} - admin.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks} - admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' } - admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' } - admin.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url + admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url, highlights_on: %r{/admin/instances}, if: -> { current_user.admin? } + admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? } + admin.item :domain_blocks, safe_join([fa_icon('lock fw'), t('admin.domain_blocks.title')]), admin_domain_blocks_url, highlights_on: %r{/admin/domain_blocks}, if: -> { current_user.admin? } + admin.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.admin? } + admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? } + admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? } + admin.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? } admin.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis} end diff --git a/config/routes.rb b/config/routes.rb index e6d6b52f7..9301a4e50 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -137,6 +137,13 @@ Rails.application.routes.draw do resource :suspension, only: [:create, :destroy] resource :confirmation, only: [:create] resources :statuses, only: [:index, :create, :update, :destroy] + + resource :role do + member do + post :promote + post :demote + end + end end resources :users, only: [] do diff --git a/db/migrate/20171109012327_add_moderator_to_accounts.rb b/db/migrate/20171109012327_add_moderator_to_accounts.rb new file mode 100644 index 000000000..ddd87583a --- /dev/null +++ b/db/migrate/20171109012327_add_moderator_to_accounts.rb @@ -0,0 +1,15 @@ +require Rails.root.join('lib', 'mastodon', 'migration_helpers') + +class AddModeratorToAccounts < ActiveRecord::Migration[5.1] + include Mastodon::MigrationHelpers + + disable_ddl_transaction! + + def up + safety_assured { add_column_with_default :users, :moderator, :bool, default: false } + end + + def down + remove_column :users, :moderator + end +end diff --git a/db/schema.rb b/db/schema.rb index 935fd79c5..f16b24fd6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20171107143624) do +ActiveRecord::Schema.define(version: 20171109012327) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -437,6 +437,7 @@ ActiveRecord::Schema.define(version: 20171107143624) do t.string "filtered_languages", default: [], null: false, array: true t.bigint "account_id", null: false t.boolean "disabled", default: false, null: false + t.boolean "moderator", default: false, null: false t.index ["account_id"], name: "index_users_on_account_id" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake index 4d519bf90..995cf0d6f 100644 --- a/lib/tasks/mastodon.rake +++ b/lib/tasks/mastodon.rake @@ -10,14 +10,41 @@ namespace :mastodon do desc 'Turn a user into an admin, identified by the USERNAME environment variable' task make_admin: :environment do include RoutingHelper + account_username = ENV.fetch('USERNAME') - user = User.joins(:account).where(accounts: { username: account_username }) + user = User.joins(:account).where(accounts: { username: account_username }) if user.present? user.update(admin: true) puts "Congrats! #{account_username} is now an admin. \\o/\nNavigate to #{edit_admin_settings_url} to get started" else - puts "User could not be found; please make sure an Account with the `#{account_username}` username exists." + puts "User could not be found; please make sure an account with the `#{account_username}` username exists." + end + end + + desc 'Turn a user into a moderator, identified by the USERNAME environment variable' + task make_mod: :environment do + account_username = ENV.fetch('USERNAME') + user = User.joins(:account).where(accounts: { username: account_username }) + + if user.present? + user.update(moderator: true) + puts "Congrats! #{account_username} is now a moderator \\o/" + else + puts "User could not be found; please make sure an account with the `#{account_username}` username exists." + end + end + + desc 'Remove admin and moderator privileges from user identified by the USERNAME environment variable' + task revoke_staff: :environment do + account_username = ENV.fetch('USERNAME') + user = User.joins(:account).where(accounts: { username: account_username }) + + if user.present? + user.update(moderator: false, admin: false) + puts "#{account_username} is no longer admin or moderator." + else + puts "User could not be found; please make sure an account with the `#{account_username}` username exists." end end -- cgit From fcb9533549e2f686af2ce9ef64c4bb6b639b9391 Mon Sep 17 00:00:00 2001 From: Marcin Mikołajczak Date: Sat, 11 Nov 2017 22:31:20 +0100 Subject: i18n: Update Polish translation (for #5635) (#5661) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * i18n: Update Polish translation (for #5635) * 😑🔫 --- config/locales/pl.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'config') diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 28eee764d..d20396810 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -62,6 +62,7 @@ pl: by_domain: Domena confirm: Potwierdź confirmed: Potwierdzono + demote: Degraduj disable: Dezaktywuj disable_two_factor_authentication: Wyłącz uwierzytelnianie dwuetapowe disabled: Dezaktywowano @@ -101,6 +102,7 @@ pl: outbox_url: Adres skrzynki nadawczej perform_full_suspension: Całkowicie zawieś profile_url: Adres profilu + promote: Podnieś uprawnienia protocol: Protokół public: Publiczne push_subscription_expires: Subskrypcja PuSH wygasa @@ -108,6 +110,11 @@ pl: reset: Resetuj reset_password: Resetuj hasło resubscribe: Ponów subskrypcję + role: Uprawnienia + roles: + admin: Administrator + moderator: Moderator + user: Użytkownik salmon_url: Adres Salmon search: Szukaj shared_inbox_url: Adres udostępnianej skrzynki @@ -343,7 +350,7 @@ pl: errors: '403': Nie masz uprawnień, aby wyświetlić tę stronę. '404': Strona, którą próbujesz odwiedzić, nie istnieje. - '410': Strona, którą próbujesz odwiedzić, już nie istnieje. + '410': Strona, którą próbujesz odwiedzić, przestała istnieć. '422': content: Sprawdzanie bezpieczeństwa nie powiodło się. Czy blokujesz pliki cookie? title: Sprawdzanie bezpieczeństwa nie powiodło się -- cgit From 252d0fe020c919bf53a42a96bffbfd342563250a Mon Sep 17 00:00:00 2001 From: KEINOS Date: Sun, 12 Nov 2017 16:51:47 +0900 Subject: Fix #5652 - Notify too short when abbrev in JA (#5664) * Fix #5652 - Notify too short when abbrev in JA Fix #5652 of the notification message to be understandable when abbreviated. * Changed quotes as original Double quote to single and single quote as none. But I am not convinced of this fix. * Added a single quote as YAMLlint's suggestion * `bundle exec i18n-tasks normalize` --- config/locales/ja.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'config') diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 0cb7d9c04..63a2495cb 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -403,8 +403,8 @@ ja: one: "新しい1件の通知 \U0001F418" other: "新しい%{count}件の通知 \U0001F418" favourite: - body: 'あなたのトゥートが %{name} さんにお気に入り登録されました:' - subject: "%{name} さんがあなたのトゥートをお気に入りに登録しました" + body: "%{name} さんにお気に入り登録された、あなたのトゥートがあります:" + subject: "%{name} さんにお気に入りに登録されました" follow: body: "%{name} さんにフォローされています" subject: "%{name} さんにフォローされています" @@ -415,8 +415,8 @@ ja: body: "%{name} さんから返信がありました:" subject: "%{name} さんに返信されました" reblog: - body: 'あなたのトゥートが %{name} さんにブーストされました:' - subject: あなたのトゥートが %{name} さんにブーストされました + body: "%{name} さんにブーストされた、あなたのトゥートがあります:" + subject: "%{name} さんにブーストされました" number: human: decimal_units: -- cgit From 0e6c4cb7964df1c2899c5a0c57cc73013d9718a1 Mon Sep 17 00:00:00 2001 From: Anna e só Date: Tue, 14 Nov 2017 00:07:38 -0200 Subject: l10n: PT-BR translation updated (#5681) * Improved e-mail messages; delted repeated words * pt-BR.json translations updated * Revert "pt-BR.json translations updated" This reverts commit 108c460531196fed6e6d14f93e8d8d047c835ffd. * Updated pt-BR.json * pt-BR.yml updated --- app/javascript/mastodon/locales/pt-BR.json | 2 +- .../confirmation_instructions.pt-BR.html.erb | 4 ++-- .../confirmation_instructions.pt-BR.text.erb | 4 ++-- .../user_mailer/password_change.pt-BR.html.erb | 2 +- .../user_mailer/password_change.pt-BR.text.erb | 2 +- .../reset_password_instructions.pt-BR.html.erb | 4 ++-- .../reset_password_instructions.pt-BR.text.erb | 4 ++-- config/locales/pt-BR.yml | 22 +++++++++++++++++++++- 8 files changed, 32 insertions(+), 12 deletions(-) (limited to 'config') diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index ddb8b83f5..a04d1cc31 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -161,7 +161,7 @@ "privacy.unlisted.short": "Não listada", "relative_time.days": "{number}d", "relative_time.hours": "{number}h", - "relative_time.just_now": "now", + "relative_time.just_now": "agora", "relative_time.minutes": "{number}m", "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Cancelar", diff --git a/app/views/user_mailer/confirmation_instructions.pt-BR.html.erb b/app/views/user_mailer/confirmation_instructions.pt-BR.html.erb index 80edcfda7..0be16d994 100644 --- a/app/views/user_mailer/confirmation_instructions.pt-BR.html.erb +++ b/app/views/user_mailer/confirmation_instructions.pt-BR.html.erb @@ -1,6 +1,6 @@

Boas vindas, <%= @resource.email %>!

-

Você acabou de criar uma conta no <%= @instance %>.

+

Você acabou de criar uma conta na instância <%= @instance %>.

Para confirmar o seu cadastro, por favor clique no link a seguir:
<%= link_to 'Confirmar cadastro', confirmation_url(@resource, confirmation_token: @token) %> @@ -9,4 +9,4 @@

Atenciosamente,

-

A equipe do <%= @instance %>

+

A equipe da instância <%= @instance %>

diff --git a/app/views/user_mailer/confirmation_instructions.pt-BR.text.erb b/app/views/user_mailer/confirmation_instructions.pt-BR.text.erb index 95efb3436..578f7acb5 100644 --- a/app/views/user_mailer/confirmation_instructions.pt-BR.text.erb +++ b/app/views/user_mailer/confirmation_instructions.pt-BR.text.erb @@ -1,6 +1,6 @@ Boas vindas, <%= @resource.email %>! -Você acabou de criar uma conta no <%= @instance %>. +Você acabou de criar uma conta na instância <%= @instance %>. Para confirmar o seu cadastro, por favor clique no link a seguir: <%= confirmation_url(@resource, confirmation_token: @token) %> @@ -9,4 +9,4 @@ Por favor, leia também os nossos termos e condições de uso <%= terms_url %> Atenciosamente, -A equipe do <%= @instance %> +A equipe da instância <%= @instance %> diff --git a/app/views/user_mailer/password_change.pt-BR.html.erb b/app/views/user_mailer/password_change.pt-BR.html.erb index 5f707ba09..a1aaa265e 100644 --- a/app/views/user_mailer/password_change.pt-BR.html.erb +++ b/app/views/user_mailer/password_change.pt-BR.html.erb @@ -1,3 +1,3 @@

Olá, <%= @resource.email %>!

-

Estamos te contatando para te notificar que a senha senha no <%= @instance %> foi modificada.

+

Estamos te contatando para te notificar que a sua senha na instância <%= @instance %> foi modificada.

diff --git a/app/views/user_mailer/password_change.pt-BR.text.erb b/app/views/user_mailer/password_change.pt-BR.text.erb index d8b76648c..eb7368ba9 100644 --- a/app/views/user_mailer/password_change.pt-BR.text.erb +++ b/app/views/user_mailer/password_change.pt-BR.text.erb @@ -1,3 +1,3 @@ Olá, <%= @resource.email %>! -Estamos te contatando para te notificar que a senha senha no <%= @instance %> foi modificada. +Estamos te contatando para te notificar que a sua senha na instância <%= @instance %> foi modificada. diff --git a/app/views/user_mailer/reset_password_instructions.pt-BR.html.erb b/app/views/user_mailer/reset_password_instructions.pt-BR.html.erb index 940438b7c..9b21aae92 100644 --- a/app/views/user_mailer/reset_password_instructions.pt-BR.html.erb +++ b/app/views/user_mailer/reset_password_instructions.pt-BR.html.erb @@ -1,8 +1,8 @@

Olá, <%= @resource.email %>!

-

Alguém solicitou um link para mudar a sua senha no <%= @instance %>. Você pode fazer isso através do link abaixo:

+

Alguém solicitou um link para mudar a sua senha na instância <%= @instance %>. Você pode fazer isso através do link abaixo:

<%= link_to 'Mudar a minha senha', edit_password_url(@resource, reset_password_token: @token) %>

Se você não solicitou isso, por favor ignore este e-mail.

-

A senha senha não será modificada até que você acesse o link acima e crie uma nova.

+

A senha não será modificada até que você acesse o link acima e crie uma nova.

diff --git a/app/views/user_mailer/reset_password_instructions.pt-BR.text.erb b/app/views/user_mailer/reset_password_instructions.pt-BR.text.erb index f574fe08f..2abff0c0d 100644 --- a/app/views/user_mailer/reset_password_instructions.pt-BR.text.erb +++ b/app/views/user_mailer/reset_password_instructions.pt-BR.text.erb @@ -1,8 +1,8 @@ Olá, <%= @resource.email %>! -Alguém solicitou um link para mudar a sua senha no <%= @instance %>. Você pode fazer isso através do link abaixo: +Alguém solicitou um link para mudar a sua senha na instância <%= @instance %>. Você pode fazer isso através do link abaixo: <%= edit_password_url(@resource, reset_password_token: @token) %> Se você não solicitou isso, por favor ignore este e-mail. -A senha senha não será modificada até que você acesse o link acima e crie uma nova. +A senha não será modificada até que você acesse o link acima e crie uma nova. diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 4b9ea152f..f5c61c01c 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -43,7 +43,7 @@ pt-BR: people_followed_by: Pessoas que %{name} segue people_who_follow: Pessoas que seguem %{name} posts: Toots - posts_with_replies: Toots com respostas + posts_with_replies: Toots e respostas remote_follow: Siga remotamente reserved_username: Este usuário está reservado roles: @@ -59,13 +59,19 @@ pt-BR: destroyed_msg: Nota de moderação excluída com sucesso! accounts: are_you_sure: Você tem certeza? + by_domain: Domínio confirm: Confirmar confirmed: Confirmado + demote: Rebaixar + disable: Desativar disable_two_factor_authentication: Desativar 2FA + disabled: Desativado display_name: Nome de exibição domain: Domínio edit: Editar email: E-mail + enable: Ativar + enabled: Ativado feed_url: URL do feed followers: Seguidores followers_url: URL de seguidores @@ -77,7 +83,9 @@ pt-BR: local: Local remote: Remoto title: Localização + login_status: Status de login media_attachments: Mídia(s) anexada(s) + memorialize: Tornar um memorial moderation: all: Todos silenced: Silenciados @@ -94,6 +102,7 @@ pt-BR: outbox_url: URL da Outbox perform_full_suspension: Efetue suspensão total profile_url: URL do perfil + promote: Promover protocol: Protocolo public: Público push_subscription_expires: Inscrição PuSH expira @@ -101,6 +110,11 @@ pt-BR: reset: Anular reset_password: Modificar senha resubscribe: Reinscrever-se + role: Permissões + roles: + admin: Administrador + moderator: Moderador + user: Usuário salmon_url: Salmon URL search: Pesquisar shared_inbox_url: URL da Inbox Compartilhada @@ -130,11 +144,16 @@ pt-BR: enable: Habilitar enabled_msg: Emoji habilitado com sucesso! image_hint: PNG de até 50KB + listed: Listado new: title: Adicionar novo emoji customizado + overwrite: Sobrescrever shortcode: Atalho shortcode_hint: Pelo menos 2 caracteres, apenas caracteres alfanuméricos e underscores title: Emojis customizados + unlisted: Não listado + update_failed_msg: Não foi possível atualizar esse emoji + updated_msg: Emoji atualizado com sucesso! upload: Enviar domain_blocks: add_new: Adicionar novo @@ -373,6 +392,7 @@ pt-BR: following: Pessoas que você segue muting: Lista de silêncio upload: Enviar + in_memoriam_html: Em memória de landing_strip_html: "%{name} é um usuário no %{link_to_root_path}. Você pode segui-lo ou interagir com ele se você tiver uma conta em qualquer lugar no fediverso." landing_strip_signup_html: Se não, você pode se cadastrar aqui. media_attachments: -- cgit From a6682a300061cfb814b09cd6937b77eb07405192 Mon Sep 17 00:00:00 2001 From: Marcin Mikołajczak Date: Tue, 14 Nov 2017 07:52:32 +0100 Subject: i18n: fix typo in Polish translation (#5688) --- config/locales/pl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config') diff --git a/config/locales/pl.yml b/config/locales/pl.yml index d20396810..f2b0e587b 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -629,7 +629,7 @@ pl: manual_instructions: 'Jeżeli nie możesz zeskanować kodu QR, musisz wprowadzić ten kod ręcznie:' recovery_codes: Przywróć kody zapasowe recovery_codes_regenerated: Pomyślnie wygenerowano ponownie kody zapasowe - recovery_instructions_html: Jeżeli kiedykolwiek utracisz dostęp do telefonu, możesz wykorzystać jeden z kodów zapasowych, aby odzyskać dostęp do konta. Trzymaj je w bezpiecznym miejscu. Na przykład, wydrukuj je i przechowuj z ważnymu dokumentami. + recovery_instructions_html: Jeżeli kiedykolwiek utracisz dostęp do telefonu, możesz wykorzystać jeden z kodów zapasowych, aby odzyskać dostęp do konta. Trzymaj je w bezpiecznym miejscu. Na przykład, wydrukuj je i przechowuj z ważnymi dokumentami. setup: Skonfiguruj wrong_code: Wprowadzony kod jest niepoprawny! Czy czas serwera i urządzenia jest poprawny? users: -- cgit From 249b0fe1079e739ed7a03e22c8a8aa928eb2fbad Mon Sep 17 00:00:00 2001 From: mayaeh Date: Tue, 14 Nov 2017 15:53:14 +0900 Subject: Add Japanese translations for moderator roles and its own admin actions. (#5689) --- config/locales/ja.yml | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'config') diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 63a2495cb..82b642b5b 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -62,6 +62,7 @@ ja: by_domain: ドメイン confirm: 確認 confirmed: 確認済み + demote: 降格 disable: 無効化 disable_two_factor_authentication: 二段階認証を無効にする disabled: 無効 @@ -101,6 +102,7 @@ ja: outbox_url: Outbox URL perform_full_suspension: 完全に活動停止させる profile_url: プロフィールURL + promote: 昇格 protocol: プロトコル public: パブリック push_subscription_expires: PuSH購読期限 @@ -108,6 +110,11 @@ ja: reset: リセット reset_password: パスワード再設定 resubscribe: 再講読 + role: 役割 + roles: + admin: 管理者 + moderator: モデレーター + user: ユーザー salmon_url: Salmon URL search: 検索 shared_inbox_url: Shared Inbox URL -- cgit From 8087aa83d414150fd1141d237ae9d7c0366fec8d Mon Sep 17 00:00:00 2001 From: Marcin Mikołajczak Date: Tue, 14 Nov 2017 20:36:11 +0100 Subject: i18n: Update Polish translation (#5699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcin Mikołajczak --- app/javascript/mastodon/locales/pl.json | 4 ++-- config/locales/pl.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'config') diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index cf76f1b1f..b23a5e69f 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -89,7 +89,7 @@ "follow_request.reject": "Odrzuć", "getting_started.appsshort": "Aplikacje", "getting_started.faq": "FAQ", - "getting_started.heading": "Naucz się korzystać", + "getting_started.heading": "Rozpocznij", "getting_started.open_source_notice": "Mastodon jest oprogramowaniem o otwartym źródle. Możesz pomóc w rozwoju lub zgłaszać błędy na GitHubie tutaj: {github}.", "getting_started.userguide": "Podręcznik użytkownika", "home.column_settings.advanced": "Zaawansowane", @@ -174,7 +174,7 @@ "search_popout.tips.status": "wpis", "search_popout.tips.text": "Proste wyszukiwanie pasujących pseudonimów, nazw użytkowników i hashtagów", "search_popout.tips.user": "użytkownik", - "search_results.total": "{count, number} {count, plural, one {wynik} more {wyniki}}", + "search_results.total": "{count, number} {count, plural, one {wynik} few {wyniki} many {wyników} more {wyników}}", "standalone.public_title": "Spojrzenie w głąb…", "status.cannot_reblog": "Ten wpis nie może zostać podbity", "status.delete": "Usuń", diff --git a/config/locales/pl.yml b/config/locales/pl.yml index f2b0e587b..49dace354 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -9,7 +9,7 @@ pl: contact_missing: Nie ustawiono contact_unavailable: Nie dotyczy description_headline: Czym jest %{domain}? - domain_count_after: instancji + domain_count_after: instancjami domain_count_before: Serwer połączony z extended_description_html: |

Dobre miejsce na zasady użytkowania

-- cgit From c3ec1e87b8c19487c954b0cc571b426b4d5b53fa Mon Sep 17 00:00:00 2001 From: SerCom_KC Date: Wed, 15 Nov 2017 03:44:42 +0800 Subject: Updating Chinese (Simplified) translations (#5643) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * i18n: (zh-CN) Bug fix for note-counter. * i18n: (zh-CN) Improve translations * i18n: (zh-CN) Improve translations * i18n: (zh-CN) Add missing translations * i18n: (zh-CN) Improve translations * i18n: (zh-CN) Add support.array key for better wording * Revert "i18n: (zh-CN) Add support.array key for better wording" This reverts commit 27bf9a946e886213e827cd985d4f62419db57534. Looks like this commit can't get pass the checks, revert it for now. * i18n: (zh-CN) Change `客户端` to `应用` * i18n: (zh-CN) Improve translations * i18n: (zh-CN) Add missing translations (#5635) * i18n: (zh-CN) Change `两步验证` to `双重认证` * i18n: (zh-CN) Improve translations --- app/javascript/mastodon/locales/zh-CN.json | 9 +++-- config/locales/devise.zh-CN.yml | 58 +++++++++++++-------------- config/locales/doorkeeper.zh-CN.yml | 63 ++++++++++++++++-------------- config/locales/simple_form.zh-CN.yml | 6 +-- config/locales/zh-CN.yml | 44 ++++++++++++++------- 5 files changed, 101 insertions(+), 79 deletions(-) (limited to 'config') diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index f0f23959a..0f4bbb7c1 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -49,9 +49,9 @@ "compose_form.placeholder": "在想啥?", "compose_form.publish": "嘟嘟", "compose_form.publish_loud": "{publish}!", - "compose_form.sensitive": "将媒体文件标记为“敏感内容”", - "compose_form.spoiler": "将部分文字隐藏于警告消息之后", - "compose_form.spoiler_placeholder": "隐藏文字的警告消息", + "compose_form.sensitive": "将媒体文件标记为敏感内容", + "compose_form.spoiler": "折叠嘟文内容", + "compose_form.spoiler_placeholder": "折叠部分的警告消息", "confirmation_modal.cancel": "取消", "confirmations.block.confirm": "屏蔽", "confirmations.block.message": "想好了,真的要屏蔽 {name}?", @@ -90,7 +90,7 @@ "getting_started.appsshort": "应用", "getting_started.faq": "常见问题", "getting_started.heading": "开始使用", - "getting_started.open_source_notice": "Mastodon 是一个开放源码的软件。你可以在官方 GitHub({github})贡献或者回报问题。", + "getting_started.open_source_notice": "Mastodon 是一个开源软件。欢迎前往 GitHub({github})贡献代码或反馈问题。", "getting_started.userguide": "用户指南", "home.column_settings.advanced": "高级设置", "home.column_settings.basic": "基本设置", @@ -204,6 +204,7 @@ "tabs_bar.home": "主页", "tabs_bar.local_timeline": "本站", "tabs_bar.notifications": "通知", + "ui.beforeunload": "如果你现在离开 Mastodon,你的草稿内容将会被丢弃。", "upload_area.title": "将文件拖放到此处开始上传", "upload_button.label": "上传媒体文件", "upload_form.description": "为视觉障碍人士添加文字说明", diff --git a/config/locales/devise.zh-CN.yml b/config/locales/devise.zh-CN.yml index 8cc814224..0e40fcc90 100644 --- a/config/locales/devise.zh-CN.yml +++ b/config/locales/devise.zh-CN.yml @@ -2,24 +2,24 @@ zh-CN: devise: confirmations: - confirmed: 成功验证您的邮箱地址。 - send_instructions: 您的电子邮箱将在几分钟后收到一封邮箱确认邮件。 - send_paranoid_instructions: 如果您的邮箱存在于我们的数据库中,您将收到一封确认帐号的邮件。 + confirmed: 成功验证你的邮箱地址。 + send_instructions: 你的电子邮箱将在几分钟后收到一封确认邮件。如果没有,请检查你的垃圾邮箱。 + send_paranoid_instructions: 如果你的邮箱存在于我们的数据库中,你将收到一封确认注册的邮件。如果没有,请检查你的垃圾邮箱。 failure: - already_authenticated: 您已经登录。 - inactive: 您还没有激活帐户。 + already_authenticated: 你已经登录。 + inactive: 你还没有激活帐户。 invalid: " %{authentication_keys} 或密码错误。" - last_attempt: 您还有最后一次尝试机会,再次失败您的帐号将被锁定。 - locked: 您的帐号已被锁定。 + last_attempt: 你还有最后一次尝试机会,再次失败你的帐户将被锁定。 + locked: 你的帐户已被锁定。 not_found_in_database: "%{authentication_keys}或密码错误。" - timeout: 您已登录超时,请重新登录。 + timeout: 你已登录超时,请重新登录。 unauthenticated: 继续操作前请注册或者登录。 - unconfirmed: 继续操作前请先确认您的帐号。 + unconfirmed: 继续操作前请先确认你的帐户。 mailer: confirmation_instructions: subject: Mastodon 帐户确认信息 email_changed: - subject: Mastodon 电邮已被修改 + subject: Mastodon 电子邮件地址已被修改 password_change: subject: Mastodon 密码已被重置 reset_password_instructions: @@ -30,33 +30,33 @@ zh-CN: failure: 由于%{reason},无法从%{kind}获得授权。 success: 成功地从%{kind}获得授权。 passwords: - no_token: 无重置邮件不可访问密码重置页面。如果您是从重置邮件来到了这个页面,请确保您输入的URL完整的。 - send_instructions: 几分钟后,您将收到重置密码的电子邮件。 - send_paranoid_instructions: 如果您的邮箱存在于我们的数据库中,您将收到一封找回密码的邮件。 - updated: 您的密码已修改成功,您现在已登录。 - updated_not_active: 您的密码已修改成功。 + no_token: 你必须通过密码重置邮件才能访问这个页面。如果你确实如此,请确保你输入的 URL 是完整的。 + send_instructions: 几分钟后,你将收到重置密码的电子邮件。如果没有,请检查你的垃圾邮箱。 + send_paranoid_instructions: 如果你的邮箱存在于我们的数据库中,你将收到一封找回密码的邮件。如果没有,请检查你的垃圾邮箱。 + updated: 你的密码已修改成功,你现在已登录。 + updated_not_active: 你的密码已修改成功。 registrations: - destroyed: 再见!您的帐户已成功注销。我们希望很快可以再见到您。 - signed_up: 欢迎!您已注册成功。 - signed_up_but_inactive: 您已注册,但尚未激活帐号。 - signed_up_but_locked: 您已注册,但帐号被锁定了。 - signed_up_but_unconfirmed: 一封带有确认链接的邮件已经发送至您的邮箱,请检查邮箱(包括垃圾邮箱),并点击该链接激活您的帐号。 - update_needs_confirmation: 信息更新成功,但我们需要验证您的新电子邮件地址,请检查邮箱(包括垃圾邮箱),并点击该链接激活您的帐号。 - updated: 帐号资料更新成功。 + destroyed: 再见!你的帐户已成功注销。我们希望很快可以再见到你。 + signed_up: 欢迎!你已注册成功。 + signed_up_but_inactive: 你已注册,但尚未激活帐户。 + signed_up_but_locked: 你已注册,但帐户被锁定了。 + signed_up_but_unconfirmed: 一封带有确认链接的邮件已经发送至你的邮箱,请点击邮件中的链接以激活你的帐户。如果没有,请检查你的垃圾邮箱。 + update_needs_confirmation: 信息更新成功,但我们需要验证你的新电子邮件地址,请点击邮件中的链接以确认。如果没有,请检查你的垃圾邮箱。 + updated: 帐户资料更新成功。 sessions: - already_signed_out: 已经退出成功。 + already_signed_out: 已成功登出。 signed_in: 登录成功。 - signed_out: 退出成功。 + signed_out: 登出成功。 unlocks: - send_instructions: 几分钟后,您将收到一封解锁帐号的邮件。 - send_paranoid_instructions: 如果您的邮箱存在于我们的数据库中,您将收到一封解锁帐号的邮件。 - unlocked: 您的帐号已成功解锁,您现在已登录。 + send_instructions: 几分钟后,你将收到一封解锁帐户的邮件。如果没有,请检查你的垃圾邮箱。 + send_paranoid_instructions: 如果你的邮箱存在于我们的数据库中,你将收到一封解锁帐户的邮件。如果没有,请检查你的垃圾邮箱。 + unlocked: 你的帐户已成功解锁。登录以继续。 errors: messages: already_confirmed: 已经确认,请重新登录。 - confirmation_period_expired: 注册帐号后须在%{period}以内确认。请重新注册。 + confirmation_period_expired: 注册帐户后须在 %{period}以内确认。请重新注册。 expired: 邮件确认已过期,请重新注册。 not_found: 找不到。 not_locked: 未锁定。 not_saved: - other: 发生%{count}个错误,导致%{resource}保存失败: + other: 发生 %{count} 个错误,导致%{resource}保存失败: diff --git a/config/locales/doorkeeper.zh-CN.yml b/config/locales/doorkeeper.zh-CN.yml index 12b38b81f..c7e8f368d 100644 --- a/config/locales/doorkeeper.zh-CN.yml +++ b/config/locales/doorkeeper.zh-CN.yml @@ -3,15 +3,16 @@ zh-CN: activerecord: attributes: doorkeeper/application: - name: 名称 - redirect_uri: 登录回调地址 + name: 应用名称 + redirect_uri: 重定向 URI scopes: 权限范围 + website: 应用网站 errors: models: doorkeeper/application: attributes: redirect_uri: - fragment_present: 不能包含片段(#) + fragment_present: 不能包含网址片段(#) invalid_uri: 必须是有效的 URL 格式 relative_uri: 必须是绝对的 URL 地址 secured_uri: 必须是 HTTPS/SSL 的 URL 地址 @@ -30,60 +31,65 @@ zh-CN: form: error: 抱歉! 提交信息的时候遇到了下面的错误 help: - native_redirect_uri: 使用 %{native_redirect_uri} 作为本地测试 + native_redirect_uri: 本地测试请使用 %{native_redirect_uri} redirect_uri: 每行只能有一个 URL - scopes: 用空格隔开权限范围,留空则使用默认设置 + scopes: 用空格分割权限范围,留空则使用默认设置 index: - callback_url: 登录回调地址 + application: 应用 + callback_url: 回调 URL + delete: 删除 name: 名称 new: 创建新应用 + scopes: 权限范围 + show: 显示 title: 你的应用 new: title: 创建新应用 show: actions: 操作 application_id: 应用 ID - callback_urls: 登录回调地址 + callback_urls: 回调 URL scopes: 权限范围 - secret: 私钥 + secret: 应用密钥 title: 应用:%{name} authorizations: buttons: - authorize: 授权 - deny: 拒绝 + authorize: 同意授权 + deny: 拒绝授权 error: - title: 存在错误 + title: 发生错误 new: - able_to: 此应用将会 - prompt: 授权 %{client_name} 使用你的帐号? - title: 需要你授权 + able_to: 此应用将能够 + prompt: 授权 %{client_name} 使用你的帐户? + title: 需要授权 show: - title: Copy this authorization code and paste it to the application. + title: 接下来请复制此处的授权代码并粘贴到应用中。 authorized_applications: buttons: - revoke: 注销 + revoke: 撤销授权 confirmations: - revoke: 确定要注销此应用的认证信息吗? + revoke: 确定要撤销对此应用的授权吗? index: application: 应用 created_at: 授权时间 date_format: "%Y-%m-%d %H:%M:%S" - title: 你授权的应用列表 + scopes: 权限范围 + title: 已授权的应用列表 errors: messages: access_denied: 用户或服务器拒绝了请求 - credential_flow_not_configured: Resource Owner Password Credentials flow failed,原因是 Doorkeeper.configure.resource_owner_from_credentials 尚未设置。 - invalid_client: 由于未知、不支持或没有客户端,认证失败 + credential_flow_not_configured: 由于 Doorkeeper.configure.resource_owner_from_credentials 尚未配置,应用验证授权流程失败。 + invalid_client: 由于应用信息未知、未提交认证信息或使用了不支持的认证方式,认证失败 invalid_grant: 授权方式无效,或者登录回调地址无效、过期或已被撤销 invalid_redirect_uri: 无效的登录回调地址 - invalid_request: 这个请求缺少必要的参数,或者参数值、格式不正确 - invalid_resource_owner: 资源所有者认证无效或没有所有者 - invalid_scope: 请求范围无效、未知或格式不正确 + invalid_request: 请求缺少必要的参数,或者参数值、格式不正确 + invalid_resource_owner: 资源所有者认证无效,或找不到所有者 + invalid_scope: 请求的权限范围无效、未知或格式不正确 invalid_token: expired: 访问令牌已过期 revoked: 访问令牌已被吊销 unknown: 访问令牌无效 - resource_owner_authenticator_not_configured: Resource Owner find failed,原因是 Doorkeeper.configure.resource_owner_authenticator 尚未设置。 + resource_owner_authenticator_not_configured: 由于 Doorkeeper.configure.resource_owner_authenticator 尚未配置,查找资源所有者失败。 server_error: 服务器异常,无法处理请求 temporarily_unavailable: 服务器维护中或负载过高,暂时无法处理请求 unauthorized_client: 未授权的应用,请求无法执行 @@ -99,16 +105,15 @@ zh-CN: notice: 应用修改成功 authorized_applications: destroy: - notice: 已成功注销了应用的认证信息 + notice: 已成功撤销对此应用的授权 layouts: admin: nav: applications: 应用 - home: 首页 oauth2_provider: OAuth2 提供商 application: - title: OAuth 认证 + title: 需要 OAuth 认证 scopes: - follow: 关注(或取消关注),屏蔽(或取消屏蔽)用户 - read: 读取你的账户数据 + follow: 关注(或取消关注)、屏蔽(或取消屏蔽)用户 + read: 读取你的帐户数据 write: 为你发表嘟文 diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml index 8bd3b576c..f8c9461ad 100644 --- a/config/locales/simple_form.zh-CN.yml +++ b/config/locales/simple_form.zh-CN.yml @@ -8,13 +8,13 @@ zh-CN: display_name: 还能输入 %{count} 个字符 header: 文件大小限制 2MB,只支持 PNG、GIF 或 JPG 格式。图片分辨率将会压缩至 700×335px locked: 你需要手动审核所有关注请求 - note: 还能输入 %{count} 个字符 + note: 还能输入 %{count} 个字符 setting_noindex: 此设置会影响到你的公开个人资料以及嘟文页面 setting_theme: 此设置会影响到你从任意设备登录时 Mastodon 的显示样式 imports: data: 请上传从其他 Mastodon 实例导出的 CSV 文件 sessions: - otp: 输入你手机上生成的两步验证码,或者任意一个恢复代码。 + otp: 输入你手机上生成的双重认证码,或者任意一个恢复代码。 user: filtered_languages: 勾选语言的嘟文将不会出现在你的公共时间轴上 labels: @@ -32,7 +32,7 @@ zh-CN: locked: 保护你的帐户(锁嘟) new_password: 新密码 note: 简介 - otp_attempt: 两步认证代码 + otp_attempt: 双重认证代码 password: 密码 setting_auto_play_gif: 自动播放 GIF 动画 setting_boost_modal: 在转嘟前询问我 diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 4a71a9959..b50c34fd0 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -59,13 +59,19 @@ zh-CN: destroyed_msg: 管理记录删除成功! accounts: are_you_sure: 你确定吗? + by_domain: 域名 confirm: 确认 confirmed: 已确认 - disable_two_factor_authentication: 停用两步认证 + demote: 降任 + disable: 停用 + disable_two_factor_authentication: 停用双重认证 + disabled: 已停用 display_name: 昵称 domain: 域名 edit: 编辑 email: 电子邮件地址 + enable: 启用 + enabled: 已启用 feed_url: 订阅 URL followers: 关注者 followers_url: 关注者(Followers)URL @@ -77,7 +83,9 @@ zh-CN: local: 本地 remote: 远程 title: 位置 + login_status: 登录状态 media_attachments: 媒体文件 + memorialize: 设置为追悼帐户 moderation: all: 全部 silenced: 已静音 @@ -94,6 +102,7 @@ zh-CN: outbox_url: 发件箱(Outbox)URL perform_full_suspension: 永久封禁 profile_url: 个人资料页面 URL + promote: 升任 protocol: 协议 public: 公开页面 push_subscription_expires: PuSH 订阅过期时间 @@ -101,6 +110,11 @@ zh-CN: reset: 重置 reset_password: 重置密码 resubscribe: 重新订阅 + role: 用户组 + roles: + admin: 管理员 + moderator: 协管 + user: 用户 salmon_url: Salmon URL search: 搜索 shared_inbox_url: 公用收件箱(Shared Inbox)URL @@ -130,18 +144,19 @@ zh-CN: enable: 启用 enabled_msg: 表情启用成功 image_hint: PNG 格式,最大 50KB - listed: 默认显示的表情 + listed: 已显示 new: title: 添加新的自定义表情 + overwrite: 覆盖 shortcode: 短代码 shortcode_hint: 至少 2 个字符,只能使用字母、数字和下划线 title: 自定义表情 - unlisted: 默认隐藏的表情 + unlisted: 已隐藏 update_failed_msg: 表情更新失败! updated_msg: 表情更新成功! upload: 上传 domain_blocks: - add_new: 添加 + add_new: 添加新条目 created_msg: 正在进行域名屏蔽 destroyed_msg: 域名屏蔽已撤销 domain: 域名 @@ -149,7 +164,7 @@ zh-CN: create: 添加域名屏蔽 hint: 域名屏蔽不会阻止该域名下的帐户进入本站的数据库,但是会对来自这个域名的帐户自动进行预先设置的管理操作。 severity: - desc_html: 选择自动静音会将该域名下帐户发送的嘟文设置为仅关注者可见;选择自动封禁会将该域名下帐户发送的嘟文、媒体文件以及个人资料数据从本实例上删除;选择可以拒绝接收来自该域名的任何媒体文件。 + desc_html: 选择自动静音会将该域名下帐户发送的嘟文设置为仅关注者可见;选择自动封禁会将该域名下帐户发送的嘟文、媒体文件以及个人资料数据从本实例上删除;如果你只是想拒绝接收来自该域名的任何媒体文件,请选择。 noop: 无 silence: 自动静音 suspend: 自动封禁 @@ -160,7 +175,7 @@ zh-CN: noop: 无 silence: 自动静音 suspend: 自动封禁 - severity: 封禁级别 + severity: 屏蔽级别 show: affected_accounts: 将会影响到数据库中的 %{count} 个帐户 retroactive: @@ -177,7 +192,7 @@ zh-CN: destroyed_msg: 电子邮件域名屏蔽删除成功 domain: 域名 new: - create: 添加封禁 + create: 添加屏蔽 title: 添加电子邮件域名屏蔽 title: 电子邮件域名屏蔽 instances: @@ -373,6 +388,7 @@ zh-CN: following: 关注列表 muting: 静音列表 upload: 上传 + in_memoriam_html: 谨此悼念。 landing_strip_html: "%{name} 是一位来自 %{link_to_root_path} 的用户。如果你想关注这个人或者与这个人互动,你需要在任意一个 Mastodon 实例或与其兼容的网站上拥有一个帐户。" landing_strip_signup_html: 还没有这种帐户?你可以在本站注册一个。 media_attachments: @@ -492,7 +508,7 @@ zh-CN: notifications: 通知 preferences: 首选项 settings: 设置 - two_factor_authentication: 两步认证 + two_factor_authentication: 双重认证 your_apps: 你的应用 statuses: open_in_web: 在站内打开 @@ -589,16 +605,16 @@ zh-CN: default: Mastodon time: formats: - default: "%Y年%-m月%d日%H:%M" + default: "%Y年%-m月%d日 %H:%M" two_factor_authentication: code_hint: 输入你的认证器生成的代码以确认 - description_html: 启用两步认证后,你需要输入手机认证器生成的代码才能登录 + description_html: 启用双重认证后,你需要输入手机认证器生成的代码才能登录 disable: 停用 enable: 启用 - enabled: 两步认证已启用 - enabled_success: 两步认证启用成功 + enabled: 双重认证已启用 + enabled_success: 双重认证启用成功 generate_recovery_codes: 生成恢复代码 - instructions_html: "请使用 Google 身份验证器或其他类似的 TOTP 两步验证手机应用扫描此处的二维码。启用两部验证后,你需要输入该应用生成的代码来登录你的帐户。" + instructions_html: "请使用 Google 身份验证器或其他 TOTP 双重认证手机应用扫描此处的二维码。启用双重认证后,你需要输入该应用生成的代码来登录你的帐户。" lost_recovery_codes: 如果你的手机不慎丢失,你可以使用恢复代码来重新获得对帐户的访问权。如果你遗失了恢复代码,可以在此处重新生成。之前使用的恢复代码将会失效。 manual_instructions: 如果你无法扫描二维码,请手动输入下列文本: recovery_codes: 备份恢复代码 @@ -608,5 +624,5 @@ zh-CN: wrong_code: 输入的认证码无效!请检查你设备上显示的时间是否正确,如果正确,你可能需要联系管理员以检查服务器的时间是否正确。 users: invalid_email: 输入的电子邮件地址无效 - invalid_otp_token: 输入的两步认证代码无效 + invalid_otp_token: 输入的双重认证代码无效 signed_in_as: 当前登录的帐户: -- cgit From fbef909c2a1ff8d24811f76237e62fbef6cc63cc Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 14 Nov 2017 21:12:57 +0100 Subject: Add option to block direct messages from people you don't follow (#5669) * Add option to block direct messages from people you don't follow Fix #5326 * If the DM responds to a toot by recipient, allow it through * i18n: Update Polish translation (for #5669) (#5673) --- .../settings/notifications_controller.rb | 2 +- app/services/notify_service.rb | 59 ++++++++++++++++++---- app/views/settings/notifications/show.html.haml | 3 +- config/locales/simple_form.en.yml | 1 + config/locales/simple_form.pl.yml | 1 + config/settings.yml | 1 + spec/services/notify_service_spec.rb | 33 ++++++++++++ 7 files changed, 89 insertions(+), 11 deletions(-) (limited to 'config') diff --git a/app/controllers/settings/notifications_controller.rb b/app/controllers/settings/notifications_controller.rb index 09839f16e..ce2530c54 100644 --- a/app/controllers/settings/notifications_controller.rb +++ b/app/controllers/settings/notifications_controller.rb @@ -26,7 +26,7 @@ class Settings::NotificationsController < ApplicationController def user_settings_params params.require(:user).permit( notification_emails: %i(follow follow_request reblog favourite mention digest), - interactions: %i(must_be_follower must_be_following) + interactions: %i(must_be_follower must_be_following must_be_following_dm) ) end end diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index ca53c61c5..6a24a8247 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -36,17 +36,58 @@ class NotifyService < BaseService false end + def following_sender? + return @following_sender if defined?(@following_sender) + @following_sender = @recipient.following?(@notification.from_account) || @recipient.requested?(@notification.from_account) + end + + def optional_non_follower? + @recipient.user.settings.interactions['must_be_follower'] && !@notification.from_account.following?(@recipient) + end + + def optional_non_following? + @recipient.user.settings.interactions['must_be_following'] && !following_sender? + end + + def direct_message? + @notification.type == :mention && @notification.target_status.direct_visibility? + end + + def response_to_recipient? + @notification.target_status.in_reply_to_account_id == @recipient.id + end + + def optional_non_following_and_direct? + direct_message? && + @recipient.user.settings.interactions['must_be_following_dm'] && + !following_sender? && + !response_to_recipient? + end + + def hellbanned? + @notification.from_account.silenced? && !following_sender? + end + + def from_self? + @recipient.id == @notification.from_account.id + end + + def domain_blocking? + @recipient.domain_blocking?(@notification.from_account.domain) && !following_sender? + end + def blocked? - blocked = @recipient.suspended? # Skip if the recipient account is suspended anyway - blocked ||= @recipient.id == @notification.from_account.id # Skip for interactions with self - blocked ||= @recipient.domain_blocking?(@notification.from_account.domain) && !@recipient.following?(@notification.from_account) # Skip for domain blocked accounts - blocked ||= @recipient.blocking?(@notification.from_account) # Skip for blocked accounts - blocked ||= @recipient.muting?(@notification.from_account) # Skip for muted accounts - blocked ||= (@notification.from_account.silenced? && !@recipient.following?(@notification.from_account)) # Hellban - blocked ||= (@recipient.user.settings.interactions['must_be_follower'] && !@notification.from_account.following?(@recipient)) # Options - blocked ||= (@recipient.user.settings.interactions['must_be_following'] && !@recipient.following?(@notification.from_account)) # Options + blocked = @recipient.suspended? # Skip if the recipient account is suspended anyway + blocked ||= from_self? # Skip for interactions with self + blocked ||= domain_blocking? # Skip for domain blocked accounts + blocked ||= @recipient.blocking?(@notification.from_account) # Skip for blocked accounts + blocked ||= @recipient.muting?(@notification.from_account) # Skip for muted accounts + blocked ||= hellbanned? # Hellban + blocked ||= optional_non_follower? # Options + blocked ||= optional_non_following? # Options + blocked ||= optional_non_following_and_direct? # Options blocked ||= conversation_muted? - blocked ||= send("blocked_#{@notification.type}?") # Type-dependent filters + blocked ||= send("blocked_#{@notification.type}?") # Type-dependent filters blocked end diff --git a/app/views/settings/notifications/show.html.haml b/app/views/settings/notifications/show.html.haml index 80cd615c7..b718b62df 100644 --- a/app/views/settings/notifications/show.html.haml +++ b/app/views/settings/notifications/show.html.haml @@ -11,7 +11,7 @@ = ff.input :reblog, as: :boolean, wrapper: :with_label = ff.input :favourite, as: :boolean, wrapper: :with_label = ff.input :mention, as: :boolean, wrapper: :with_label - + .fields-group = f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff| = ff.input :digest, as: :boolean, wrapper: :with_label @@ -20,6 +20,7 @@ = f.simple_fields_for :interactions, hash_to_object(current_user.settings.interactions) do |ff| = ff.input :must_be_follower, as: :boolean, wrapper: :with_label = ff.input :must_be_following, as: :boolean, wrapper: :with_label + = ff.input :must_be_following_dm, as: :boolean, wrapper: :with_label .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index aafae48ce..faf41f316 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -54,6 +54,7 @@ en: interactions: must_be_follower: Block notifications from non-followers must_be_following: Block notifications from people you don't follow + must_be_following_dm: Block direct messages from people you don't follow notification_emails: digest: Send digest e-mails favourite: Send e-mail when someone favourites your status diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml index 68f84d109..8b539662c 100644 --- a/config/locales/simple_form.pl.yml +++ b/config/locales/simple_form.pl.yml @@ -58,6 +58,7 @@ pl: interactions: must_be_follower: Nie wyświetlaj powiadomień od osób, które Cię nie śledzą must_be_following: Nie wyświetlaj powiadomień od osób, których nie śledzisz + must_be_following_dm: Nie wyświetlaj wiadomości bezpośrednich od osób, których nie śledzisz notification_emails: digest: Wysyłaj podsumowania e-mailem favourite: Powiadamiaj mnie e-mailem, gdy ktoś polubi mój wpis diff --git a/config/settings.yml b/config/settings.yml index 11681d7ec..a4df4094d 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -36,6 +36,7 @@ defaults: &defaults interactions: must_be_follower: false must_be_following: false + must_be_following_dm: false reserved_usernames: - admin - support diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb index 7a66bd0fe..58ee66ded 100644 --- a/spec/services/notify_service_spec.rb +++ b/spec/services/notify_service_spec.rb @@ -38,6 +38,39 @@ RSpec.describe NotifyService do is_expected.to_not change(Notification, :count) end + context 'for direct messages' do + let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct)) } + + before do + user.settings.interactions = user.settings.interactions.merge('must_be_following_dm' => enabled) + end + + context 'if recipient is supposed to be following sender' do + let(:enabled) { true } + + it 'does not notify' do + is_expected.to_not change(Notification, :count) + end + + context 'if the message chain initiated by recipient' do + let(:reply_to) { Fabricate(:status, account: recipient) } + let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct, thread: reply_to)) } + + it 'does notify' do + is_expected.to change(Notification, :count) + end + end + end + + context 'if recipient is NOT supposed to be following sender' do + let(:enabled) { false } + + it 'does notify' do + is_expected.to change(Notification, :count) + end + end + end + context do let(:asshole) { Fabricate(:account, username: 'asshole') } let(:reply_to) { Fabricate(:status, account: asshole) } -- cgit From 546257bc7f75538993470b1a53f2095f801c069d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 14 Nov 2017 23:22:43 +0100 Subject: Allow specifying STATSD_NAMESPACE (#5700) --- config/initializers/statsd.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'config') diff --git a/config/initializers/statsd.rb b/config/initializers/statsd.rb index 17a176174..45702ac94 100644 --- a/config/initializers/statsd.rb +++ b/config/initializers/statsd.rb @@ -4,7 +4,7 @@ if ENV['STATSD_ADDR'].present? host, port = ENV['STATSD_ADDR'].split(':') statsd = ::Statsd.new(host, port) - statsd.namespace = ['Mastodon', Rails.env].join('.') + statsd.namespace = ENV.fetch('STATSD_NAMESPACE') { ['Mastodon', Rails.env].join('.') } ::NSA.inform_statsd(statsd) do |informant| informant.collect(:action_controller, :web) -- cgit From f6bc6399e223b9bf91f01f0f4c5c6597a928f400 Mon Sep 17 00:00:00 2001 From: mayaeh Date: Wed, 15 Nov 2017 11:57:09 +0900 Subject: Add Japanese translation for DM block option. (#5704) --- config/locales/simple_form.ja.yml | 1 + 1 file changed, 1 insertion(+) (limited to 'config') diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 993eae706..48eaf79b2 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -50,6 +50,7 @@ ja: interactions: must_be_follower: フォロワー以外からの通知をブロック must_be_following: フォローしていないユーザーからの通知をブロック + must_be_following_dm: フォローしていないユーザーからのダイレクトメッセージをブロック notification_emails: digest: タイムラインからピックアップしてメールで通知する favourite: お気に入りに登録された時にメールで通知する -- cgit