Commit 97be095e30b29a6b7f1534d3b4653b6e54b16eb9
1 parent
9744f0d3
message
Showing
33 changed files
with
1321 additions
and
76 deletions
Show diff stats
backend/config/main.php
@@ -23,6 +23,16 @@ return [ | @@ -23,6 +23,16 @@ return [ | ||
23 | ], | 23 | ], |
24 | ], | 24 | ], |
25 | 'components' => [ | 25 | 'components' => [ |
26 | + 'mailer' => [ | ||
27 | + 'class' => 'yii\swiftmailer\Mailer', | ||
28 | + 'transport' => [ | ||
29 | + 'class' => 'Swift_SpoolTransport', | ||
30 | + 'constructArgs' => [ | ||
31 | + 'spool' => new common\components\DbSpool(), | ||
32 | + ] | ||
33 | + ], | ||
34 | + 'useFileTransport' => false, | ||
35 | + ], | ||
26 | 'user' => [ | 36 | 'user' => [ |
27 | 'identityClass' => 'common\models\User', | 37 | 'identityClass' => 'common\models\User', |
28 | 'enableAutoLogin' => true, | 38 | 'enableAutoLogin' => true, |
backend/config/params.php
1 | +<?php | ||
2 | +namespace backend\controllers; | ||
3 | + | ||
4 | +use backend\models\Language; | ||
5 | +use backend\models\MessageLang; | ||
6 | +use backend\models\Message; | ||
7 | +use yii\web\Controller; | ||
8 | +use yii\web\ForbiddenHttpException; | ||
9 | +use yii\web\NotFoundHttpException; | ||
10 | + | ||
11 | +class AjaxController extends Controller | ||
12 | +{ | ||
13 | + public function beforeAction($action) | ||
14 | + { | ||
15 | + if(!\Yii::$app->request->getIsAjax()) { | ||
16 | + //throw new ForbiddenHttpException('Permission denied'); | ||
17 | + } | ||
18 | + | ||
19 | + if(!parent::beforeAction($action)) { | ||
20 | + return false; | ||
21 | + } | ||
22 | + | ||
23 | + return true; | ||
24 | + } | ||
25 | + public function actionMessageForm($lang_id, $widget_id) | ||
26 | + { | ||
27 | + $model = Language::find()->where(['>=', 'language_id', 1])->andWhere(['active' => 1, 'language_id' => $lang_id])->one(); | ||
28 | + if(!$model) { | ||
29 | + throw new NotFoundHttpException('Language not found'); | ||
30 | + } | ||
31 | + $message_lang = new MessageLang(); | ||
32 | + return $this->renderAjax('message_form', ['model' => $model, 'message_lang' => $message_lang, 'widget_id' => $widget_id]); | ||
33 | + } | ||
34 | + | ||
35 | + /* public function actionRemoveImage() | ||
36 | + { | ||
37 | + $post = \Yii::$app->request->post(); | ||
38 | + if(!empty($post['article_media_id'])) { | ||
39 | + $article_media = ArticleMedia::findOne($post['article_media_id']); | ||
40 | + if($post['remove_media']) { | ||
41 | + $media = $article_media->media->delete(); | ||
42 | + } | ||
43 | + if(!empty($article_media)) { | ||
44 | + $article_media->delete(); | ||
45 | + } | ||
46 | + return true; | ||
47 | + } else { | ||
48 | + return false; | ||
49 | + } | ||
50 | + } | ||
51 | + | ||
52 | + public function actionRemoveImageCategory() | ||
53 | + { | ||
54 | + $post = \Yii::$app->request->post(); | ||
55 | + if(!empty($post['category_media_id'])) { | ||
56 | + $category_media = ArticleCategoryMedia::findOne($post['category_media_id']); | ||
57 | + if($post['remove_media']) { | ||
58 | + $media = $category_media->media->delete(); | ||
59 | + } | ||
60 | + if(!empty($category_media)) { | ||
61 | + $category_media->delete(); | ||
62 | + } | ||
63 | + return true; | ||
64 | + } else { | ||
65 | + return false; | ||
66 | + } | ||
67 | + }*/ | ||
68 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace backend\controllers; | ||
4 | + | ||
5 | +use backend\models\Message; | ||
6 | +use backend\models\MessageLang; | ||
7 | +use Yii; | ||
8 | +use common\models\MailerQueue; | ||
9 | +use common\components\DbSpool; | ||
10 | +use yii\data\ActiveDataProvider; | ||
11 | +use yii\web\Controller; | ||
12 | +use yii\web\NotFoundHttpException; | ||
13 | +use yii\filters\VerbFilter; | ||
14 | + | ||
15 | +/** | ||
16 | + * MailerQueueController implements the CRUD actions for MailerQueue model. | ||
17 | + */ | ||
18 | +class MailerQueueController extends Controller | ||
19 | +{ | ||
20 | + public function behaviors() | ||
21 | + { | ||
22 | + return [ | ||
23 | + 'verbs' => [ | ||
24 | + 'class' => VerbFilter::className(), | ||
25 | + 'actions' => [ | ||
26 | + 'delete' => ['post'], | ||
27 | + ], | ||
28 | + ], | ||
29 | + ]; | ||
30 | + } | ||
31 | + | ||
32 | + /** | ||
33 | + * @param integer $id message id | ||
34 | + * add message to queue | ||
35 | + */ | ||
36 | + public function actionSpooler($id) | ||
37 | + { | ||
38 | + $curr_lang=2; | ||
39 | + $message_tempalete = Message::findOne(['id'=>$id]); | ||
40 | + $message_template_langs = $message_tempalete->getMessageLangs()->where(['>=', 'lang_id', '1'])->indexBy('lang_id')->all(); | ||
41 | + $message = \Swift_Message::newInstance(); | ||
42 | + $spool = new DbSpool(); | ||
43 | + $transport = \Swift_SpoolTransport::newInstance($spool); | ||
44 | + $mailer = \Swift_Mailer::newInstance($transport); | ||
45 | + foreach ($message_template_langs as $message_template_lang) | ||
46 | + { | ||
47 | + if($message_template_lang->lang_id == $curr_lang ) | ||
48 | + { | ||
49 | + $message ->setSubject($message_template_lang->title) | ||
50 | + ->setFrom('info@example.com') | ||
51 | + ->setTo('alexandr.khivrich@gmail.com') | ||
52 | + ->setBody($message_template_lang->body); | ||
53 | + if($message_template_lang->is_html) | ||
54 | + { | ||
55 | + $message ->setContentType('text\html'); | ||
56 | + } | ||
57 | + break; | ||
58 | + } | ||
59 | + } | ||
60 | + $result = $mailer->send($message); | ||
61 | + } | ||
62 | + | ||
63 | + /** | ||
64 | + * Send Queue messages | ||
65 | + */ | ||
66 | + public function actionSend() | ||
67 | + { | ||
68 | + $messageLimit = 10; | ||
69 | + $timeLimit = 0; | ||
70 | + | ||
71 | + $spool = new DbSpool(); | ||
72 | + //$transportReal = \Swift_MailTransport::newInstance(); | ||
73 | + $transportReal = \Swift_SmtpTransport::newInstance( | ||
74 | + "smtp.gmail.com", | ||
75 | + "465", | ||
76 | + "ssl" | ||
77 | + ) | ||
78 | + ->setUsername("alexandr.khivrich@gmail.com") | ||
79 | + ->setPassword("10181997Nadia"); | ||
80 | + | ||
81 | + $spool->setMessageLimit($messageLimit); | ||
82 | + $spool->setTimeLimit($timeLimit); | ||
83 | + $sent = $spool->flushQueue($transportReal); | ||
84 | + | ||
85 | + echo sprintf('sent %s emails', $sent); | ||
86 | + } | ||
87 | + /** | ||
88 | + * Finds the MailerQueue model based on its primary key value. | ||
89 | + * If the model is not found, a 404 HTTP exception will be thrown. | ||
90 | + * @param integer $id | ||
91 | + * @return MailerQueue the loaded model | ||
92 | + * @throws NotFoundHttpException if the model cannot be found | ||
93 | + */ | ||
94 | + protected function findModel($id) | ||
95 | + { | ||
96 | + if (($model = MailerQueue::findOne($id)) !== null) { | ||
97 | + return $model; | ||
98 | + } else { | ||
99 | + throw new NotFoundHttpException('The requested page does not exist.'); | ||
100 | + } | ||
101 | + } | ||
102 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace backend\controllers; | ||
4 | +use common\models\Language; | ||
5 | +use backend\models\MessageLang; | ||
6 | +use Yii; | ||
7 | +use backend\models\Message; | ||
8 | +use app\models\MessageSearch; | ||
9 | +use yii\web\Controller; | ||
10 | +use yii\web\NotFoundHttpException; | ||
11 | +use yii\filters\VerbFilter; | ||
12 | +use yii\data\ActiveDataProvider; | ||
13 | +/** | ||
14 | + * MessageController implements the CRUD actions for Message model. | ||
15 | + */ | ||
16 | +class MessageController extends Controller | ||
17 | +{ | ||
18 | + public function behaviors() | ||
19 | + { | ||
20 | + return [ | ||
21 | + 'verbs' => [ | ||
22 | + 'class' => VerbFilter::className(), | ||
23 | + 'actions' => [ | ||
24 | + 'delete' => ['post'], | ||
25 | + ], | ||
26 | + ], | ||
27 | + ]; | ||
28 | + } | ||
29 | + | ||
30 | + /** | ||
31 | + * Lists all Message models. | ||
32 | + * @return mixed | ||
33 | + */ | ||
34 | + public function actionIndex() | ||
35 | + { | ||
36 | + $searchModel = new MessageSearch(); | ||
37 | + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); | ||
38 | + | ||
39 | + return $this->render('index', [ | ||
40 | + 'searchModel' => $searchModel, | ||
41 | + 'dataProvider' => $dataProvider, | ||
42 | + ]); | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * Displays a single Message model. | ||
47 | + * @param integer $id | ||
48 | + * @return mixed | ||
49 | + */ | ||
50 | + public function actionView($id) | ||
51 | + { | ||
52 | + return $this->render('view', [ | ||
53 | + 'model' => $this->findModel($id), | ||
54 | + 'model_lang'=>$model_lang = MessageLang::findOne(['message_id'=>$id]) | ||
55 | + ]); | ||
56 | + } | ||
57 | + | ||
58 | + /** | ||
59 | + * Creates a new Message model. | ||
60 | + * If creation is successful, the browser will be redirected to the 'view' page. | ||
61 | + * @return mixed | ||
62 | + */ | ||
63 | + public function actionCreate() | ||
64 | + { | ||
65 | + $message_langs = array(); | ||
66 | + $message = new Message(); | ||
67 | + $images = array(); | ||
68 | + $message->loadDefaultValues(); | ||
69 | + $langs = Language::getActiveLanguages(); | ||
70 | + $default_lang = Language::getDefaultLang(); | ||
71 | + $isValid = false; | ||
72 | + | ||
73 | + if(!empty(\Yii::$app->request->post())) | ||
74 | + { | ||
75 | + | ||
76 | + $isValid = true; | ||
77 | + $message->load(\Yii::$app->request->post()); | ||
78 | + $isValid = $message->validate(); | ||
79 | + if(empty(\Yii::$app->request->post()['MessageLang'])) | ||
80 | + { | ||
81 | + | ||
82 | + $message_langs[$default_lang->language_id] = new MessageLang(); | ||
83 | + $isValid = MessageLang::validateMultiple($message_langs) && $isValid; | ||
84 | + } | ||
85 | + else | ||
86 | + { | ||
87 | + foreach(\Yii::$app->request->post()['MessageLang'] as $index => $message_lang) { | ||
88 | + $message_langs[$index] = new MessageLang(); | ||
89 | + } | ||
90 | + MessageLang::loadMultiple($message_langs, \Yii::$app->request->post()); | ||
91 | + // $isValid = MessageLang::validateMultiple($message_langs) && $isValid; | ||
92 | + } | ||
93 | + } | ||
94 | + else | ||
95 | + { | ||
96 | + $message_langs[$default_lang->language_id] = new MessageLang(); | ||
97 | + } | ||
98 | + if($isValid) | ||
99 | + { | ||
100 | + $message->save(); | ||
101 | + $first = 1; | ||
102 | + foreach($message_langs as $message_lang) { | ||
103 | + $message_lang->message_id=$message->id; | ||
104 | + $message_lang->save(); | ||
105 | + } | ||
106 | + $this->redirect('index'); | ||
107 | + } | ||
108 | + else | ||
109 | + { | ||
110 | + return $this->render('create', [ | ||
111 | + 'message_langs' => $message_langs, | ||
112 | + 'message' => $message, | ||
113 | + 'langs' => $langs, | ||
114 | + ]); | ||
115 | + } | ||
116 | + } | ||
117 | + | ||
118 | + /** | ||
119 | + * Updates an existing Message model. | ||
120 | + * If update is successful, the browser will be redirected to the 'view' page. | ||
121 | + * @param integer $id | ||
122 | + * @return mixed | ||
123 | + */ | ||
124 | + public function actionUpdate($id) | ||
125 | + { | ||
126 | + $message = $this->findModel($id); | ||
127 | + $message_langs=$message->getMessageLangs()->where(['>=', 'lang_id', '1'])->indexBy('lang_id')->all(); | ||
128 | + $langs = Language::getActiveLanguages(); | ||
129 | + $default_lang = Language::getDefaultLang(); | ||
130 | + $isValid = false; | ||
131 | + $post=\Yii::$app->request->post(); | ||
132 | + if(!empty($post)) | ||
133 | + { | ||
134 | + $message->load($post); | ||
135 | + $isValid = $message->validate(); | ||
136 | + } | ||
137 | + if(empty($post['MessageLang'])) | ||
138 | + { | ||
139 | + $isValid = MessageLang::validateMultiple($message_langs) && $isValid; | ||
140 | + } | ||
141 | + else | ||
142 | + { | ||
143 | + foreach($post['MessageLang'] as $index => $message_lang) | ||
144 | + { | ||
145 | + if (!array_key_exists($index, $message_langs)) | ||
146 | + { | ||
147 | + $message_langs[$index] = new MessageLang(); | ||
148 | + $message_langs[$index]->message_id = $message->id; | ||
149 | + } | ||
150 | + } | ||
151 | + MessageLang::loadMultiple($message_langs,$post); | ||
152 | + } | ||
153 | + if($isValid) | ||
154 | + { | ||
155 | + $message->save(); | ||
156 | + $first = 1; | ||
157 | + foreach($message_langs as $message_lang) { | ||
158 | + $message_lang->message_id=$message->id; | ||
159 | + $message_lang->save(); | ||
160 | + } | ||
161 | + $this->redirect('index'); | ||
162 | + } | ||
163 | + else | ||
164 | + { | ||
165 | + return $this->render('update', [ | ||
166 | + 'message_langs' => $message_langs, | ||
167 | + 'message' => $message, | ||
168 | + 'langs' => $langs, | ||
169 | + ]); | ||
170 | + } | ||
171 | + } | ||
172 | + | ||
173 | + /** | ||
174 | + * Deletes an existing Message model. | ||
175 | + * If deletion is successful, the browser will be redirected to the 'index' page. | ||
176 | + * @param integer $id | ||
177 | + * @return mixed | ||
178 | + */ | ||
179 | + public function actionDelete($id) | ||
180 | + { | ||
181 | + foreach(MessageLang::findAll(['message_id'=>$id])as $message_lang) | ||
182 | + { | ||
183 | + $message_lang->delete(); | ||
184 | + } | ||
185 | + | ||
186 | + $this->findModel($id)->delete(); | ||
187 | + return $this->redirect(['index']); | ||
188 | + } | ||
189 | + | ||
190 | + /** | ||
191 | + * Finds the Message model based on its primary key value. | ||
192 | + * If the model is not found, a 404 HTTP exception will be thrown. | ||
193 | + * @param integer $id | ||
194 | + * @return Message the loaded model | ||
195 | + * @throws NotFoundHttpException if the model cannot be found | ||
196 | + */ | ||
197 | + protected function findModel($id) | ||
198 | + { | ||
199 | + if (($model = Message::findOne($id)) !== null) { | ||
200 | + return $model; | ||
201 | + } else { | ||
202 | + throw new NotFoundHttpException('The requested page does not exist.'); | ||
203 | + } | ||
204 | + } | ||
205 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace backend\models; | ||
4 | + | ||
5 | +use Yii; | ||
6 | + | ||
7 | +/** | ||
8 | + * This is the model class for table "message". | ||
9 | + * | ||
10 | + * @property integer $id | ||
11 | + * @property string $name | ||
12 | + * @property boolean $is_sevice_sender | ||
13 | + * @property boolean $is_server_sender | ||
14 | + * @property boolean $is_sms | ||
15 | + * | ||
16 | + * @property MessageLang[] $messageLangs | ||
17 | + */ | ||
18 | +class Message extends \yii\db\ActiveRecord | ||
19 | +{ | ||
20 | + /** | ||
21 | + * @inheritdoc | ||
22 | + */ | ||
23 | + public static function tableName() | ||
24 | + { | ||
25 | + return 'message'; | ||
26 | + } | ||
27 | + | ||
28 | + /** | ||
29 | + * @inheritdoc | ||
30 | + */ | ||
31 | + public function rules() | ||
32 | + { | ||
33 | + return [ | ||
34 | + [['is_sevice_sender', 'is_sevice_sender', 'is_sms'], 'boolean'], | ||
35 | + [['name'], 'string', 'max' => 255] | ||
36 | + ]; | ||
37 | + } | ||
38 | + | ||
39 | + /** | ||
40 | + * @inheritdoc | ||
41 | + */ | ||
42 | + public function attributeLabels() | ||
43 | + { | ||
44 | + return [ | ||
45 | + 'id' => 'ID', | ||
46 | + 'name' => 'Name', | ||
47 | + 'is_sevice_sender' => 'Sevice sender', | ||
48 | + 'is_server_sender' => 'Server sender', | ||
49 | + 'is_sms' => 'Is SMS', | ||
50 | + ]; | ||
51 | + } | ||
52 | + | ||
53 | + /** | ||
54 | + * @return \yii\db\ActiveQuery | ||
55 | + */ | ||
56 | + public function getMessageLangs() | ||
57 | + { | ||
58 | + return $this->hasMany(MessageLang::className(), ['message_id' => 'id']); | ||
59 | + } | ||
60 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace backend\models; | ||
4 | + | ||
5 | +use Yii; | ||
6 | + | ||
7 | +/** | ||
8 | + * This is the model class for table "message_lang". | ||
9 | + * | ||
10 | + * @property string $body | ||
11 | + * @property string $title | ||
12 | + * @property integer $lang_id | ||
13 | + * @property string $body_sms | ||
14 | + * @property boolean $is_html | ||
15 | + * @property integer $message_id | ||
16 | + * @property integer $id | ||
17 | + * | ||
18 | + * @property Language $lang | ||
19 | + * @property Message $message | ||
20 | + */ | ||
21 | +class MessageLang extends \yii\db\ActiveRecord | ||
22 | +{ | ||
23 | + /** | ||
24 | + * @inheritdoc | ||
25 | + */ | ||
26 | + public static function tableName() | ||
27 | + { | ||
28 | + return 'message_lang'; | ||
29 | + } | ||
30 | + | ||
31 | + /** | ||
32 | + * @inheritdoc | ||
33 | + */ | ||
34 | + public function rules() | ||
35 | + { | ||
36 | + return [ | ||
37 | + [['body', 'message_id'], 'required'], | ||
38 | + [['body', 'body_sms'], 'string'], | ||
39 | + [['lang_id', 'message_id'], 'integer'], | ||
40 | + [['is_html'], 'boolean'], | ||
41 | + [['title'], 'string', 'max' => 255] | ||
42 | + ]; | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * @inheritdoc | ||
47 | + */ | ||
48 | + public function attributeLabels() | ||
49 | + { | ||
50 | + return [ | ||
51 | + 'body' => 'Body', | ||
52 | + 'title' => 'Title', | ||
53 | + 'lang_id' => 'Lang ID', | ||
54 | + 'body_sms' => 'SMS', | ||
55 | + 'is_html' => 'Is Html', | ||
56 | + 'message_id' => 'Message ID', | ||
57 | + 'id' => 'ID', | ||
58 | + ]; | ||
59 | + } | ||
60 | + | ||
61 | + /** | ||
62 | + * @return \yii\db\ActiveQuery | ||
63 | + */ | ||
64 | + public function getLang() | ||
65 | + { | ||
66 | + return $this->hasOne(Language::className(), ['language_id' => 'lang_id']); | ||
67 | + } | ||
68 | + | ||
69 | + /** | ||
70 | + * @return \yii\db\ActiveQuery | ||
71 | + */ | ||
72 | + public function getMessage() | ||
73 | + { | ||
74 | + return $this->hasOne(Message::className(), ['id' => 'message_id']); | ||
75 | + } | ||
76 | +} |
1 | +<?php | ||
2 | + | ||
3 | +namespace app\models; | ||
4 | + | ||
5 | +use Yii; | ||
6 | +use yii\base\Model; | ||
7 | +use yii\data\ActiveDataProvider; | ||
8 | +use backend\models\Message; | ||
9 | + | ||
10 | +/** | ||
11 | + * MessageSearch represents the model behind the search form about `backend\models\Message`. | ||
12 | + */ | ||
13 | +class MessageSearch extends Message | ||
14 | +{ | ||
15 | + /** | ||
16 | + * @inheritdoc | ||
17 | + */ | ||
18 | + public function rules() | ||
19 | + { | ||
20 | + return [ | ||
21 | + [['id'], 'integer'], | ||
22 | + [['name'], 'safe'], | ||
23 | + ]; | ||
24 | + } | ||
25 | + | ||
26 | + /** | ||
27 | + * @inheritdoc | ||
28 | + */ | ||
29 | + public function scenarios() | ||
30 | + { | ||
31 | + // bypass scenarios() implementation in the parent class | ||
32 | + return Model::scenarios(); | ||
33 | + } | ||
34 | + | ||
35 | + /** | ||
36 | + * Creates data provider instance with search query applied | ||
37 | + * | ||
38 | + * @param array $params | ||
39 | + * | ||
40 | + * @return ActiveDataProvider | ||
41 | + */ | ||
42 | + public function search($params) | ||
43 | + { | ||
44 | + $query = Message::find(); | ||
45 | + | ||
46 | + $dataProvider = new ActiveDataProvider([ | ||
47 | + 'query' => $query, | ||
48 | + ]); | ||
49 | + | ||
50 | + $this->load($params); | ||
51 | + | ||
52 | + if (!$this->validate()) { | ||
53 | + // uncomment the following line if you do not want to return any records when validation fails | ||
54 | + // $query->where('0=1'); | ||
55 | + return $dataProvider; | ||
56 | + } | ||
57 | + | ||
58 | + $query->andFilterWhere([ | ||
59 | + 'id' => $this->id, | ||
60 | + ]); | ||
61 | + | ||
62 | + $query->andFilterWhere(['like', 'name', $this->name]); | ||
63 | + | ||
64 | + return $dataProvider; | ||
65 | + } | ||
66 | +} |
1 | +<?php | ||
2 | + | ||
3 | +use yii\bootstrap\ActiveField; | ||
4 | +use mihaildev\ckeditor\CKEditor; | ||
5 | + | ||
6 | +$form = \yii\bootstrap\ActiveForm::begin(); | ||
7 | +?> | ||
8 | +<div role="" class="tab-pane active ajax-loaded" id="<?=$widget_id?>-<?=$model->language_id?>"> | ||
9 | + | ||
10 | + <?= (new ActiveField(['model' => $message_lang, 'attribute' => "[$model->language_id]lang_id"]))->label(false)->hiddenInput(['value' => $model->language_id]) ?> | ||
11 | + | ||
12 | + <?= (new ActiveField(['model' => $message_lang, 'attribute' => "[$model->language_id]title", 'form' => $form]))->textInput() ?> | ||
13 | + | ||
14 | + <?= (new ActiveField(['model' => $message_lang, 'attribute' => "[$model->language_id]body", 'form' => $form]))->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ], ]); ?> | ||
15 | + | ||
16 | + <?= (new ActiveField(['model' => $message_lang, 'attribute' => "[$model->language_id]body_sms"]))->textarea() ?> | ||
17 | +</div> | ||
18 | +<?php | ||
19 | +$form->end(); | ||
20 | +?> |
backend/views/language/index.php
@@ -24,7 +24,7 @@ echo $this->render('layout'); | @@ -24,7 +24,7 @@ echo $this->render('layout'); | ||
24 | [ | 24 | [ |
25 | 'class' => Column::className(), | 25 | 'class' => Column::className(), |
26 | 'content' => function($model, $key, $index, $column) { | 26 | 'content' => function($model, $key, $index, $column) { |
27 | - return '<span class="f32"><span class="flag '.$model->country_code.'"></span></span>'; | 27 | + return '<span class="f32"><span class="flag '.$model->lang_code.'"></span></span>'; |
28 | } | 28 | } |
29 | ], | 29 | ], |
30 | 'language_name', | 30 | 'language_name', |
backend/views/layouts/left.php
@@ -38,6 +38,7 @@ | @@ -38,6 +38,7 @@ | ||
38 | ['label' => 'Gii', 'icon' => 'fa fa-file-code-o', 'url' => ['/gii']], | 38 | ['label' => 'Gii', 'icon' => 'fa fa-file-code-o', 'url' => ['/gii']], |
39 | ['label' => 'Debug', 'icon' => 'fa fa-dashboard', 'url' => ['/debug']], | 39 | ['label' => 'Debug', 'icon' => 'fa fa-dashboard', 'url' => ['/debug']], |
40 | ['label' => 'Login', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest], | 40 | ['label' => 'Login', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest], |
41 | + ['label'=>'Messages','url'=>['/message']], | ||
41 | ['label' => 'Пользователи', 'icon' => 'fa fa-file-code-o', 'url' => ['/user/']], | 42 | ['label' => 'Пользователи', 'icon' => 'fa fa-file-code-o', 'url' => ['/user/']], |
42 | [ | 43 | [ |
43 | 'label' => Yii::t('app', 'Blog'), | 44 | 'label' => Yii::t('app', 'Blog'), |
1 | +<?php | ||
2 | + | ||
3 | +use yii\helpers\Html; | ||
4 | +use common\widgets\Multilang; | ||
5 | +use mihaildev\ckeditor\CKEditor; | ||
6 | +use yii\bootstrap\ActiveForm; | ||
7 | +use yii\helpers\Json; | ||
8 | +use yii\helpers\Url; | ||
9 | +use yii\widgets\Pjax; | ||
10 | +use backend\models\Message; | ||
11 | +use yii\helpers\ArrayHelper; | ||
12 | +/* @var $this yii\web\View */ | ||
13 | +/* @var $model backend\models\Message */ | ||
14 | +/* @var $form yii\widgets\ActiveForm */ | ||
15 | +$def_lang = array_keys($langs)[0]; | ||
16 | +?> | ||
17 | + | ||
18 | +<div class="message-form"> | ||
19 | + <?php $form = \yii\bootstrap\ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?> | ||
20 | + <?= $form->field($message,'name')->textInput()?> | ||
21 | + <?= $form->field($message,'is_sevice_sender')->checkbox()?> | ||
22 | + <?= $form->field($message,'is_server_sender')->checkbox()?> | ||
23 | + <?= $form->field($message,'is_sms')->checkbox()?> | ||
24 | + <?php | ||
25 | + $multilang = Multilang::begin(['ajaxpath' => Url::to(['/ajax/message-form']), 'form' => $form, 'data_langs' => $message_langs]); | ||
26 | + ?> | ||
27 | + <?php | ||
28 | + $first = 1; | ||
29 | + foreach($message_langs as $index => $message_lang) { | ||
30 | + ?> | ||
31 | + <div role="" class="tab-pane <?php if($first) { echo 'active main-tab'; } ?>" id="<?=$multilang->id?>-<?=$index?>"> | ||
32 | + | ||
33 | + <?= $form->field($message_langs[$index], "[$index]lang_id")->label(false)->hiddenInput(['value' =>$index]) ?> | ||
34 | + | ||
35 | + <?= $form->field($message_langs[$index], "[$index]title")->textInput() ?> | ||
36 | + | ||
37 | + <?= $form->field($message_langs[$index], "[$index]body")->widget(CKEditor::className(),['editorOptions' => [ 'preset' => 'full', 'inline' => false, ], ]); ?> | ||
38 | + | ||
39 | + <?= $form->field($message_langs[$index], "[$index]body_sms")->textarea()?> | ||
40 | + </div> | ||
41 | + <?php | ||
42 | + $first = 0; | ||
43 | + } | ||
44 | + ?> | ||
45 | + <?php | ||
46 | + $multilang->end(); | ||
47 | + ?> | ||
48 | + <div class="form-group"> | ||
49 | + <?= Html::submitButton($message->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> | ||
50 | + </div> | ||
51 | + <?php ActiveForm::end(); ?> | ||
52 | + | ||
53 | +</div> |
1 | +<?php | ||
2 | + | ||
3 | +use yii\helpers\Html; | ||
4 | +use yii\widgets\ActiveForm; | ||
5 | + | ||
6 | +/* @var $this yii\web\View */ | ||
7 | +/* @var $model app\models\MessageSearch */ | ||
8 | +/* @var $form yii\widgets\ActiveForm */ | ||
9 | +?> | ||
10 | + | ||
11 | +<div class="message-search"> | ||
12 | + | ||
13 | + <?php $form = ActiveForm::begin([ | ||
14 | + 'action' => ['index'], | ||
15 | + 'method' => 'get', | ||
16 | + ]); ?> | ||
17 | + | ||
18 | + <?= $form->field($model, 'id') ?> | ||
19 | + | ||
20 | + <?= $form->field($model, 'name') ?> | ||
21 | + | ||
22 | + <div class="form-group"> | ||
23 | + <?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?> | ||
24 | + <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?> | ||
25 | + </div> | ||
26 | + | ||
27 | + <?php ActiveForm::end(); ?> | ||
28 | + | ||
29 | +</div> |
1 | +<?php | ||
2 | + | ||
3 | +use yii\helpers\Html; | ||
4 | + | ||
5 | + | ||
6 | +/* @var $this yii\web\View */ | ||
7 | +/* @var $model backend\models\Message */ | ||
8 | + | ||
9 | +$this->title = 'Create Message'; | ||
10 | +$this->params['breadcrumbs'][] = ['label' => 'Messages', 'url' => ['index']]; | ||
11 | +$this->params['breadcrumbs'][] = $this->title; | ||
12 | +?> | ||
13 | +<div class="message-create"> | ||
14 | + | ||
15 | + <h1><?= Html::encode($this->title) ?></h1> | ||
16 | + | ||
17 | + <?= $this->render('_form', [ | ||
18 | + 'message_langs' => $message_langs, | ||
19 | + 'message' => $message, | ||
20 | + 'langs' => $langs, | ||
21 | + ]) ?> | ||
22 | + | ||
23 | +</div> |
1 | +<?php | ||
2 | + | ||
3 | +use yii\helpers\Html; | ||
4 | +use yii\grid\GridView; | ||
5 | + | ||
6 | +/* @var $this yii\web\View */ | ||
7 | +/* @var $searchModel app\models\MessageSearch */ | ||
8 | +/* @var $dataProvider yii\data\ActiveDataProvider */ | ||
9 | + | ||
10 | +$this->title = 'Messages'; | ||
11 | +$this->params['breadcrumbs'][] = $this->title; | ||
12 | +?> | ||
13 | +<div class="message-index"> | ||
14 | + | ||
15 | + <h1><?= Html::encode($this->title) ?></h1> | ||
16 | + <?php // echo $this->render('_search', ['model' => $searchModel]); ?> | ||
17 | + | ||
18 | + <p> | ||
19 | + <?= Html::a('Create Message', ['create'], ['class' => 'btn btn-success']) ?> | ||
20 | + </p> | ||
21 | + | ||
22 | + <?= GridView::widget([ | ||
23 | + 'dataProvider' => $dataProvider, | ||
24 | + 'filterModel' => $searchModel, | ||
25 | + 'columns' => [ | ||
26 | + ['class' => 'yii\grid\SerialColumn'], | ||
27 | + | ||
28 | + 'id', | ||
29 | + 'name', | ||
30 | + | ||
31 | + ['class' => 'yii\grid\ActionColumn'], | ||
32 | + ], | ||
33 | + ]); ?> | ||
34 | + | ||
35 | +</div> |
1 | +<?php | ||
2 | + | ||
3 | +use yii\helpers\Html; | ||
4 | + | ||
5 | +/* @var $this yii\web\View */ | ||
6 | +/* @var $model backend\models\Message */ | ||
7 | + | ||
8 | +$this->title = 'Update Message: ' . ' ' . $model->name; | ||
9 | +$this->params['breadcrumbs'][] = ['label' => 'Messages', 'url' => ['index']]; | ||
10 | +$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]]; | ||
11 | +$this->params['breadcrumbs'][] = 'Update'; | ||
12 | +?> | ||
13 | +<div class="message-update"> | ||
14 | + | ||
15 | + <h1><?= Html::encode($this->title) ?></h1> | ||
16 | + | ||
17 | + <?= $this->render('_form', [ | ||
18 | + 'message_langs' => $message_langs, | ||
19 | + 'message' => $message, | ||
20 | + 'langs' => $langs, | ||
21 | + ]) ?> | ||
22 | + | ||
23 | +</div> |
1 | +<?php | ||
2 | + | ||
3 | +use yii\helpers\Html; | ||
4 | +use yii\widgets\DetailView; | ||
5 | + | ||
6 | +/* @var $this yii\web\View */ | ||
7 | +/* @var $model backend\models\Message */ | ||
8 | + | ||
9 | +$this->title = $model->name; | ||
10 | +$this->params['breadcrumbs'][] = ['label' => 'Messages', 'url' => ['index']]; | ||
11 | +$this->params['breadcrumbs'][] = $this->title; | ||
12 | +?> | ||
13 | +<div class="message-view"> | ||
14 | + | ||
15 | + <h1><?= Html::encode($this->title) ?></h1> | ||
16 | + | ||
17 | + <p> | ||
18 | + <?= Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?> | ||
19 | + <?= Html::a('Delete', ['delete', 'id' => $model->id], [ | ||
20 | + 'class' => 'btn btn-danger', | ||
21 | + 'data' => [ | ||
22 | + 'confirm' => 'Are you sure you want to delete this item?', | ||
23 | + 'method' => 'post', | ||
24 | + ], | ||
25 | + ]) ?> | ||
26 | + </p> | ||
27 | + | ||
28 | + <?= DetailView::widget([ | ||
29 | + 'model' => $model, | ||
30 | + 'attributes' => [ | ||
31 | + 'id', | ||
32 | + 'name', | ||
33 | + [ | ||
34 | + 'label'=>'Lang', | ||
35 | + 'value'=>$model_lang->lang->language_name | ||
36 | + ] | ||
37 | + ], | ||
38 | + ]) ?> | ||
39 | + | ||
40 | +</div> |
backend/web/js/option.js
@@ -36,42 +36,6 @@ $(function() { | @@ -36,42 +36,6 @@ $(function() { | ||
36 | $(document).on('click', '.remove_lang', function() { | 36 | $(document).on('click', '.remove_lang', function() { |
37 | $(this).parents('.form-wrapper').remove(); | 37 | $(this).parents('.form-wrapper').remove(); |
38 | }); | 38 | }); |
39 | - if($('#lang-tabs li').length > 1) { | ||
40 | - $('#lang-tabs li').append('<span class="glyphicon glyphicon-remove-circle remove-lang"></span>') | ||
41 | - } | ||
42 | - $(document).on('click', '#lang-dropdown li a[data-lang]', function() { | ||
43 | - var lang = $(this).data('lang'); | ||
44 | - var flag = $(this).find('span').first().clone(); | ||
45 | - var el = $(this); | ||
46 | - $.get('/blog/ajax/category-form', { lang_id: lang }, function(data) { | ||
47 | - $('#lang-tabs li').removeClass('active'); | ||
48 | - $('#lang-tabs').append('<li role="lang_inputs" class="active" data-lang="'+lang+'"><a href="#lang-'+lang+'" aria-controls="lang-'+lang+'" role="tab" data-toggle="tab">'+$('<p>').append($(flag)).html()+'</a></li>'); | ||
49 | - $('.lang-tab-content .tab-pane.active').removeClass('active'); | ||
50 | - $('.lang-tab-content').append($(data).find('.ajax-loaded').first()); | ||
51 | - $('body').append($(data).filter('script')); | ||
52 | - $(el).parent().remove(); | ||
53 | - if(!$('#lang-dropdown li').length) { | ||
54 | - $('#dropdownLang').addClass('disabled'); | ||
55 | - } | ||
56 | - if($('#lang-tabs li').length > 1) { | ||
57 | - $('#lang-tabs li').append('<span class="glyphicon glyphicon-remove-circle remove-lang"></span>') | ||
58 | - } | ||
59 | - }); | ||
60 | - }); | ||
61 | - $(document).on('click', '.remove-lang', function() { | ||
62 | - var lang = $(this).parent().data('lang'); | ||
63 | - var flag = $(this).parent().find('span.flag').first().clone(); | ||
64 | - $('#lang-'+lang).remove(); | ||
65 | - $('#lang-dropdown').append('<li><a href="#lang-tabs" data-lang="'+lang+'">'+$('<p>').append($(flag)).html()+'</a></li>'); | ||
66 | - $('#dropdownLang').removeClass('disabled'); | ||
67 | - $(this).parent().remove(); | ||
68 | - if($('#lang-tabs li').length <= 1) { | ||
69 | - $('#lang-tabs li').find('.remove-lang').remove(); | ||
70 | - } | ||
71 | - if(!$('#lang-tabs>li.active').length) { | ||
72 | - $('#lang-tabs>li').first().find('a').tab('show'); | ||
73 | - } | ||
74 | - }); | ||
75 | $(document).on('change', '.image_inputs_field', function() { | 39 | $(document).on('change', '.image_inputs_field', function() { |
76 | readURL(this); | 40 | readURL(this); |
77 | }); | 41 | }); |
@@ -89,4 +53,55 @@ $(function() { | @@ -89,4 +53,55 @@ $(function() { | ||
89 | } | 53 | } |
90 | return false; | 54 | return false; |
91 | }); | 55 | }); |
56 | + $.each($('.nav-tabs.f32'), function(key, value) { | ||
57 | + if($(value).find('li').length > 1) { | ||
58 | + $(value).find('li').append('<span class="glyphicon glyphicon-remove-circle remove-lang"></span>'); | ||
59 | + } | ||
60 | + }); | ||
61 | + $(document).on('click', '.dropdown-menu.f32 li a[data-lang]', function() { | ||
62 | + var lang = $(this).data('lang'); | ||
63 | + var flag = $(this).find('span').first().clone(); | ||
64 | + var el = $(this); | ||
65 | + var id = $(this).attr('href').substr(1); | ||
66 | + $.get(form[id], { lang_id: lang, widget_id: id }, function(data) { | ||
67 | + $('#'+id+'-tabs li').removeClass('active'); | ||
68 | + $('#'+id+'-tabs').append('<li role="lang_inputs" class="active" data-lang="'+lang+'"><a href="#'+id+'-'+lang+'" aria-controls="'+id+'-'+lang+'" role="tab" data-toggle="tab">'+$('<p>').append($(flag)).html()+'</a></li>'); | ||
69 | + $('#tab-content-'+id+' .tab-pane.active').removeClass('active'); | ||
70 | + $('#tab-content-'+id).append($(data).find('.ajax-loaded').first()); | ||
71 | + $('body').append($(data).filter('script')); | ||
72 | + $(el).parent().remove(); | ||
73 | + if(!$('#lang-'+id+' li').length) { | ||
74 | + $('#'+id+'Lang').addClass('disabled'); | ||
75 | + } | ||
76 | + if($('#'+id+'-tabs li').length > 1) { | ||
77 | + $('#'+id+'-tabs li').append('<span class="glyphicon glyphicon-remove-circle remove-lang"></span>') | ||
78 | + } | ||
79 | + }); | ||
80 | + }); | ||
81 | + $(document).on('click', '.remove-lang', function() { | ||
82 | + var lang = $(this).parent().data('lang'); | ||
83 | + var flag = $(this).parent().find('span.flag').first().clone(); | ||
84 | + var id = $(this).parent().find('a[aria-controls]').first().attr('aria-controls').substr(0,8); | ||
85 | + $('#'+id+'-'+lang).remove(); | ||
86 | + $('#lang-'+id).append('<li><a href="#'+id+'" data-lang="'+lang+'">'+$('<p>').append($(flag)).html()+'</a></li>'); | ||
87 | + $('#'+id+'Lang').removeClass('disabled'); | ||
88 | + $(this).parent().remove(); | ||
89 | + if($('#'+id+'-tabs li').length <= 1) { | ||
90 | + $('#'+id+'-tabs li').find('.remove-lang').remove(); | ||
91 | + } | ||
92 | + if(!$('#'+id+'-tabs>li.active').length) { | ||
93 | + $('#'+id+'-tabs>li').first().find('a').tab('show'); | ||
94 | + } | ||
95 | + }); | ||
96 | + $('#message-is_sms').change() | ||
97 | + { | ||
98 | + if ($('#message-is_sms').is(":checked")) | ||
99 | + { | ||
100 | + | ||
101 | + $(".field-message-cmctext").css({'display': 'block'}); | ||
102 | + } | ||
103 | + else { | ||
104 | + $(".field-message-cmctext").css({'display': 'none'}); | ||
105 | + } | ||
106 | + } | ||
92 | }); | 107 | }); |
93 | \ No newline at end of file | 108 | \ No newline at end of file |
1 | +<?php | ||
2 | +namespace common\components; | ||
3 | +use common\models\MailerQueue; | ||
4 | +use yii\swiftmailer\Message; | ||
5 | +use yii\helpers\HtmlPurifier; | ||
6 | +use yii\helpers\Json; | ||
7 | + | ||
8 | +class DbSpool extends \Swift_ConfigurableSpool | ||
9 | +{ | ||
10 | + | ||
11 | + /** | ||
12 | + * File WriteRetry Limit | ||
13 | + * | ||
14 | + * @var int | ||
15 | + */ | ||
16 | + private $_retryLimit = 10; | ||
17 | + | ||
18 | +// /** | ||
19 | +// * Create a new DbSpool. | ||
20 | +// * | ||
21 | +// * @param string $path | ||
22 | +// | ||
23 | +// */ | ||
24 | + public function __construct() | ||
25 | + { | ||
26 | + | ||
27 | + } | ||
28 | + public function __destruct() | ||
29 | + { | ||
30 | + /* if (method_exists($this->_cache, 'clearAll')) | ||
31 | + { | ||
32 | + $this->_cache->clearAll($this->_cacheKey); | ||
33 | + }*/ | ||
34 | + } | ||
35 | + /** | ||
36 | + * Tests if this Spool mechanism has started. | ||
37 | + * | ||
38 | + * @return bool | ||
39 | + */ | ||
40 | + public function isStarted() | ||
41 | + { | ||
42 | + return true; | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * Starts this Spool mechanism. | ||
47 | + */ | ||
48 | + public function start() | ||
49 | + { | ||
50 | + | ||
51 | + } | ||
52 | + | ||
53 | + /** | ||
54 | + * Stops this Spool mechanism. | ||
55 | + */ | ||
56 | + public function stop() | ||
57 | + { | ||
58 | + | ||
59 | + } | ||
60 | + | ||
61 | + /** | ||
62 | + * Allow to manage the enqueuing retry limit. | ||
63 | + * | ||
64 | + * Default, is ten and allows over 64^20 different fileNames | ||
65 | + * | ||
66 | + * @param int $limit | ||
67 | + */ | ||
68 | + public function setRetryLimit($limit) | ||
69 | + { | ||
70 | + $this->_retryLimit = $limit; | ||
71 | + } | ||
72 | + | ||
73 | + /** | ||
74 | + * Queues a message. | ||
75 | + * | ||
76 | + * @param Swift_Mime_Message $message The message to store | ||
77 | + * | ||
78 | + * @return bool | ||
79 | + * | ||
80 | + * @throws Swift_IoException | ||
81 | + */ | ||
82 | + public function queueMessage(\Swift_Mime_Message $message) | ||
83 | + { | ||
84 | + | ||
85 | + $message->getBody(); | ||
86 | + $queueObject = new MailerQueue(); | ||
87 | + | ||
88 | + $queueObject->text_body = $message->getBody(); | ||
89 | + $queueObject->subject = $message->getSubject(); | ||
90 | + $queueObject->to = Json::encode($message->getTo()); | ||
91 | + $queueObject->save(); | ||
92 | + } | ||
93 | + | ||
94 | + /** | ||
95 | + * Sends messages using the given transport instance. | ||
96 | + * | ||
97 | + * @param Swift_Transport $transport A transport instance | ||
98 | + * @param string[] $failedRecipients An array of failures by-reference | ||
99 | + * | ||
100 | + * @return int The number of sent e-mail's | ||
101 | + */ | ||
102 | + public function flushQueue(\Swift_Transport $transport, &$failedRecipients = null) | ||
103 | + { | ||
104 | + if (!$transport->isStarted()) | ||
105 | + { | ||
106 | + $transport->start(); | ||
107 | + } | ||
108 | + | ||
109 | + $failedRecipients = (array) $failedRecipients; | ||
110 | + | ||
111 | + $count = 0; | ||
112 | + $emails = MailerQueue::find() | ||
113 | + ->where('sent_time IS NULL') | ||
114 | + ->orderBy('id') | ||
115 | + ->all(); | ||
116 | + | ||
117 | + if (!count($emails)) | ||
118 | + { | ||
119 | + return 0; | ||
120 | + } | ||
121 | + // print_r($emails); | ||
122 | + foreach($emails as $email) | ||
123 | + { | ||
124 | + //$message = unserialize($email->message_object); | ||
125 | + | ||
126 | + $message = \Swift_Message::newInstance($email->subject) | ||
127 | + ->setFrom(array('info@example.com' => 'ArtWeb')) | ||
128 | + ->setTo(Json::decode($email->to)) | ||
129 | + ->setBody($email->text_body); | ||
130 | + try | ||
131 | + { | ||
132 | + $count+= $transport->send($message, $failedRecipients); | ||
133 | + if($count > 0) | ||
134 | + { | ||
135 | + | ||
136 | + $time = new \DateTime(); | ||
137 | + $email->setAttribute('sent_time', $time->format('Y-m-d H:i:s')); | ||
138 | + $email->save(); | ||
139 | + } | ||
140 | + else | ||
141 | + { | ||
142 | + throw new \Swift_SwiftException('The email was not sent.'); | ||
143 | + } | ||
144 | + } | ||
145 | + catch(\Swift_SwiftException $ex) | ||
146 | + { | ||
147 | + | ||
148 | + } | ||
149 | + } | ||
150 | + return $count; | ||
151 | + } | ||
152 | +} | ||
153 | + |
common/config/main.php
@@ -166,7 +166,17 @@ return [ | @@ -166,7 +166,17 @@ return [ | ||
166 | /*========End======= | 166 | /*========End======= |
167 | *end api sicial | 167 | *end api sicial |
168 | * */ | 168 | * */ |
169 | - | 169 | + 'mailer' => [ |
170 | + 'class' => 'yii\swiftmailer\Mailer', | ||
171 | + 'transport' => [ | ||
172 | + 'class' => 'Swift_SmtpTransport', | ||
173 | + 'host' => 'smtp.gmail.com', // e.g. smtp.mandrillapp.com or smtp.gmail.com | ||
174 | + 'username' => 'alexandr.khivrich@gmail.com', | ||
175 | + 'password' => '10181997Nadia', | ||
176 | + 'port' => '587', // Port 25 is a very common port too | ||
177 | + 'encryption' => 'tls', // It is often used, check your provider or mail servers | ||
178 | + ] | ||
179 | + ], | ||
170 | ], | 180 | ], |
171 | 'language' => 'ru-RU' | 181 | 'language' => 'ru-RU' |
172 | ]; | 182 | ]; |
1 | +<?php | ||
2 | + | ||
3 | +namespace common\models; | ||
4 | + | ||
5 | +use Yii; | ||
6 | + | ||
7 | +/** | ||
8 | + * This is the model class for table "mailer_queue". | ||
9 | + * | ||
10 | + * @property integer $id | ||
11 | + * @property string $sent_time | ||
12 | + * @property string $to | ||
13 | + * @property string $text_body | ||
14 | + * @property string $charset | ||
15 | + * @property string $subject | ||
16 | + */ | ||
17 | +class MailerQueue extends \yii\db\ActiveRecord | ||
18 | +{ | ||
19 | + /** | ||
20 | + * @inheritdoc | ||
21 | + */ | ||
22 | + public static function tableName() | ||
23 | + { | ||
24 | + return 'mailer_queue'; | ||
25 | + } | ||
26 | + | ||
27 | + /** | ||
28 | + * @inheritdoc | ||
29 | + */ | ||
30 | + public function rules() | ||
31 | + { | ||
32 | + return [ | ||
33 | + [['sent_time'], 'safe'], | ||
34 | + [['text_body'], 'string'], | ||
35 | + [['to', 'subject'], 'string', 'max' => 255] | ||
36 | + ]; | ||
37 | + } | ||
38 | + | ||
39 | + /** | ||
40 | + * @inheritdoc | ||
41 | + */ | ||
42 | + public function attributeLabels() | ||
43 | + { | ||
44 | + return [ | ||
45 | + 'id' => 'ID', | ||
46 | + 'sent_time' => 'Sent Time', | ||
47 | + 'to' => 'To', | ||
48 | + 'text_body' => 'Text Body', | ||
49 | + 'subject' => 'Subject', | ||
50 | + ]; | ||
51 | + } | ||
52 | +} |
1 | +<?php | ||
2 | +namespace common\widgets; | ||
3 | +use common\models\Language; | ||
4 | +use yii\base\InvalidParamException; | ||
5 | +use yii\base\Widget; | ||
6 | +use yii\bootstrap\ActiveForm; | ||
7 | + | ||
8 | +class Multilang extends Widget | ||
9 | +{ | ||
10 | + public $id; | ||
11 | + | ||
12 | + public $langs; | ||
13 | + | ||
14 | + public $data_langs = []; | ||
15 | + | ||
16 | + public $ajaxpath; | ||
17 | + | ||
18 | + public $form; | ||
19 | + | ||
20 | + public function init() | ||
21 | + { | ||
22 | + parent::init(); | ||
23 | + if(empty($this->id)) | ||
24 | + { | ||
25 | + $this->id = \Yii::$app->security->generateRandomString(8); | ||
26 | + } | ||
27 | + if(empty($this->langs)) | ||
28 | + { | ||
29 | + $this->langs = Language::getActiveLanguages(); | ||
30 | + } | ||
31 | + if(empty($this->ajaxpath)) | ||
32 | + { | ||
33 | + throw new InvalidParamException('ajaxpath must be set'); | ||
34 | + } | ||
35 | + if(empty($this->form)) | ||
36 | + { | ||
37 | + throw new InvalidParamException('form must be set'); | ||
38 | + } | ||
39 | + ob_start(); | ||
40 | + echo $this->render('multilang-begin', ['id' => $this->id, 'langs' => $this->langs, 'data_langs' => $this->data_langs, 'ajaxpath' => $this->ajaxpath, 'form' => $this->form]); | ||
41 | + } | ||
42 | + | ||
43 | + public function run() | ||
44 | + { | ||
45 | + echo $this->render('multilang-end', ['id' => $this->id, 'langs' => $this->langs, 'data_langs' => $this->data_langs, 'ajaxpath' => $this->ajaxpath, 'form' => $this->form]); | ||
46 | + $content = ob_get_clean(); | ||
47 | + return $content; | ||
48 | + } | ||
49 | +} | ||
0 | \ No newline at end of file | 50 | \ No newline at end of file |
1 | +<?php | ||
2 | +use yii\helpers\Url; | ||
3 | +?> | ||
4 | +<div class="dropdown pull-right"> | ||
5 | + <button class="btn btn-default dropdown-toggle" type="button" id="<?=$id?>Lang" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> | ||
6 | + <?= Yii::t('app', 'Add language') ?> | ||
7 | + <span class="caret"></span> | ||
8 | + </button> | ||
9 | + <ul class="dropdown-menu f32" id="lang-<?=$id?>" aria-labelledby="<?=$id?>Menu"> | ||
10 | + <?php foreach($langs as $index => $lang) { | ||
11 | + if(in_array($index, array_keys($data_langs))) continue; | ||
12 | + ?> | ||
13 | + <li><a href="#<?=$id?>" data-lang="<?=$lang->language_id?>"><span class="flag <?=$lang->lang_code?>"></span></a></li> | ||
14 | + <?php } ?> | ||
15 | + </ul> | ||
16 | +</div> | ||
17 | +<ul class="nav nav-tabs f32" id="<?=$id?>-tabs" role="tablist"> | ||
18 | + <?php | ||
19 | + $first = 1; | ||
20 | + foreach($data_langs as $index => $data_lang) { | ||
21 | + ?> | ||
22 | + <li role="lang_inputs" class="<?php if($first) { echo 'active'; }?>" data-lang="<?=$index?>"><a href="#<?=$id?>-<?=$index?>" aria-controls="<?=$id?>-<?=$index?>" role="tab" data-toggle="tab"><span class="flag <?=$langs[$index]->lang_code?>"></span></a></li> | ||
23 | + <?php | ||
24 | + $first = 0; | ||
25 | + } | ||
26 | + ?> | ||
27 | +</ul> | ||
28 | +<div class="tab-content lang-tab-content" id="tab-content-<?=$id?>"> | ||
29 | + |
composer.json
@@ -23,7 +23,8 @@ | @@ -23,7 +23,8 @@ | ||
23 | "kartik-v/yii2-widget-select2": "@dev", | 23 | "kartik-v/yii2-widget-select2": "@dev", |
24 | "mihaildev/yii2-ckeditor": "*", | 24 | "mihaildev/yii2-ckeditor": "*", |
25 | "developeruz/yii2-db-rbac": "*", | 25 | "developeruz/yii2-db-rbac": "*", |
26 | - "nodge/yii2-eauth": "*" | 26 | + "nodge/yii2-eauth": "*", |
27 | + "iutbay/yii2-kcfinder": "*" | ||
27 | }, | 28 | }, |
28 | "require-dev": { | 29 | "require-dev": { |
29 | "yiisoft/yii2-codeception": "*", | 30 | "yiisoft/yii2-codeception": "*", |
1 | +<?php | ||
2 | + | ||
3 | +namespace backend\controllers; | ||
4 | + | ||
5 | +use Yii; | ||
6 | +use common\components\DbSpool; | ||
7 | +use yii\data\ActiveDataProvider; | ||
8 | +use yii\web\Controller; | ||
9 | +use yii\web\NotFoundHttpException; | ||
10 | +use yii\filters\VerbFilter; | ||
11 | + | ||
12 | +/** | ||
13 | + * MailerQueueController implements the CRUD actions for MailerQueue model. | ||
14 | + */ | ||
15 | +class MailerQueueController extends Controller | ||
16 | +{ | ||
17 | + public function behaviors() | ||
18 | + { | ||
19 | + return [ | ||
20 | + 'verbs' => [ | ||
21 | + 'class' => VerbFilter::className(), | ||
22 | + 'actions' => [ | ||
23 | + 'delete' => ['post'], | ||
24 | + ], | ||
25 | + ], | ||
26 | + ]; | ||
27 | + } | ||
28 | + /** | ||
29 | + * Send Queue messages | ||
30 | + */ | ||
31 | + public function actionSend() | ||
32 | + { | ||
33 | + $messageLimit = 10; | ||
34 | + $timeLimit = 0; | ||
35 | + | ||
36 | + $spool = new DbSpool(); | ||
37 | + $transportReal = \Swift_SmtpTransport::newInstance( | ||
38 | + "smtp.gmail.com", | ||
39 | + "465", | ||
40 | + "ssl" | ||
41 | + ) | ||
42 | + ->setUsername("alexandr.khivrich@gmail.com") | ||
43 | + ->setPassword("10181997Nadia"); | ||
44 | + | ||
45 | + $spool->setMessageLimit($messageLimit); | ||
46 | + $spool->setTimeLimit($timeLimit); | ||
47 | + $sent = $spool->flushQueue($transportReal); | ||
48 | + | ||
49 | + echo sprintf('sent %s emails', $sent); | ||
50 | + } | ||
51 | +} |
frontend/models/OptionValues.php
@@ -73,7 +73,7 @@ class OptionValues extends \yii\db\ActiveRecord | @@ -73,7 +73,7 @@ class OptionValues extends \yii\db\ActiveRecord | ||
73 | } | 73 | } |
74 | return $langs; | 74 | return $langs; |
75 | } | 75 | } |
76 | - public function beforeSave($insert) { | 76 | + public function beforeSave($insert){ |
77 | if (parent::beforeSave($insert)) { | 77 | if (parent::beforeSave($insert)) { |
78 | $this->option_user = \Yii::$app->user->getId(); | 78 | $this->option_user = \Yii::$app->user->getId(); |
79 | if($this->option_value_parent == 0) { | 79 | if($this->option_value_parent == 0) { |
frontend/web/js/option.js
@@ -36,42 +36,6 @@ $(function() { | @@ -36,42 +36,6 @@ $(function() { | ||
36 | $(document).on('click', '.remove_lang', function() { | 36 | $(document).on('click', '.remove_lang', function() { |
37 | $(this).parents('.form-wrapper').remove(); | 37 | $(this).parents('.form-wrapper').remove(); |
38 | }); | 38 | }); |
39 | - if($('#lang-tabs li').length > 1) { | ||
40 | - $('#lang-tabs li').append('<span class="glyphicon glyphicon-remove-circle remove-lang"></span>') | ||
41 | - } | ||
42 | - $(document).on('click', '#lang-dropdown li a[data-lang]', function() { | ||
43 | - var lang = $(this).data('lang'); | ||
44 | - var flag = $(this).find('span').first().clone(); | ||
45 | - var el = $(this); | ||
46 | - $.get('/blog/ajax/category-form', { lang_id: lang }, function(data) { | ||
47 | - $('#lang-tabs li').removeClass('active'); | ||
48 | - $('#lang-tabs').append('<li role="lang_inputs" class="active" data-lang="'+lang+'"><a href="#lang-'+lang+'" aria-controls="lang-'+lang+'" role="tab" data-toggle="tab">'+$('<p>').append($(flag)).html()+'</a></li>'); | ||
49 | - $('.lang-tab-content .tab-pane.active').removeClass('active'); | ||
50 | - $('.lang-tab-content').append($(data).find('.ajax-loaded').first()); | ||
51 | - $('body').append($(data).filter('script')); | ||
52 | - $(el).parent().remove(); | ||
53 | - if(!$('#lang-dropdown li').length) { | ||
54 | - $('#dropdownLang').addClass('disabled'); | ||
55 | - } | ||
56 | - if($('#lang-tabs li').length > 1) { | ||
57 | - $('#lang-tabs li').append('<span class="glyphicon glyphicon-remove-circle remove-lang"></span>') | ||
58 | - } | ||
59 | - }); | ||
60 | - }); | ||
61 | - $(document).on('click', '.remove-lang', function() { | ||
62 | - var lang = $(this).parent().data('lang'); | ||
63 | - var flag = $(this).parent().find('span.flag').first().clone(); | ||
64 | - $('#lang-'+lang).remove(); | ||
65 | - $('#lang-dropdown').append('<li><a href="#lang-tabs" data-lang="'+lang+'">'+$('<p>').append($(flag)).html()+'</a></li>'); | ||
66 | - $('#dropdownLang').removeClass('disabled'); | ||
67 | - $(this).parent().remove(); | ||
68 | - if($('#lang-tabs li').length <= 1) { | ||
69 | - $('#lang-tabs li').find('.remove-lang').remove(); | ||
70 | - } | ||
71 | - if(!$('#lang-tabs>li.active').length) { | ||
72 | - $('#lang-tabs>li').first().find('a').tab('show'); | ||
73 | - } | ||
74 | - }); | ||
75 | $(document).on('change', '.image_inputs_field', function() { | 39 | $(document).on('change', '.image_inputs_field', function() { |
76 | readURL(this); | 40 | readURL(this); |
77 | }); | 41 | }); |
@@ -89,4 +53,44 @@ $(function() { | @@ -89,4 +53,44 @@ $(function() { | ||
89 | } | 53 | } |
90 | return false; | 54 | return false; |
91 | }); | 55 | }); |
56 | + $.each($('.nav-tabs.f32'), function(key, value) { | ||
57 | + if($(value).find('li').length > 1) { | ||
58 | + $(value).find('li').append('<span class="glyphicon glyphicon-remove-circle remove-lang"></span>'); | ||
59 | + } | ||
60 | + }); | ||
61 | + $(document).on('click', '.dropdown-menu.f32 li a[data-lang]', function() { | ||
62 | + var lang = $(this).data('lang'); | ||
63 | + var flag = $(this).find('span').first().clone(); | ||
64 | + var el = $(this); | ||
65 | + var id = $(this).attr('href').substr(1); | ||
66 | + $.get(form[id], { lang_id: lang, widget_id: id }, function(data) { | ||
67 | + $('#'+id+'-tabs li').removeClass('active'); | ||
68 | + $('#'+id+'-tabs').append('<li role="lang_inputs" class="active" data-lang="'+lang+'"><a href="#'+id+'-'+lang+'" aria-controls="'+id+'-'+lang+'" role="tab" data-toggle="tab">'+$('<p>').append($(flag)).html()+'</a></li>'); | ||
69 | + $('#tab-content-'+id+' .tab-pane.active').removeClass('active'); | ||
70 | + $('#tab-content-'+id).append($(data).find('.ajax-loaded').first()); | ||
71 | + $('body').append($(data).filter('script')); | ||
72 | + $(el).parent().remove(); | ||
73 | + if(!$('#lang-'+id+' li').length) { | ||
74 | + $('#'+id+'Lang').addClass('disabled'); | ||
75 | + } | ||
76 | + if($('#'+id+'-tabs li').length > 1) { | ||
77 | + $('#'+id+'-tabs li').append('<span class="glyphicon glyphicon-remove-circle remove-lang"></span>') | ||
78 | + } | ||
79 | + }); | ||
80 | + }); | ||
81 | + $(document).on('click', '.remove-lang', function() { | ||
82 | + var lang = $(this).parent().data('lang'); | ||
83 | + var flag = $(this).parent().find('span.flag').first().clone(); | ||
84 | + var id = $(this).parent().find('a[aria-controls]').first().attr('aria-controls').substr(0,8); | ||
85 | + $('#'+id+'-'+lang).remove(); | ||
86 | + $('#lang-'+id).append('<li><a href="#'+id+'" data-lang="'+lang+'">'+$('<p>').append($(flag)).html()+'</a></li>'); | ||
87 | + $('#'+id+'Lang').removeClass('disabled'); | ||
88 | + $(this).parent().remove(); | ||
89 | + if($('#'+id+'-tabs li').length <= 1) { | ||
90 | + $('#'+id+'-tabs li').find('.remove-lang').remove(); | ||
91 | + } | ||
92 | + if(!$('#'+id+'-tabs>li.active').length) { | ||
93 | + $('#'+id+'-tabs>li').first().find('a').tab('show'); | ||
94 | + } | ||
95 | + }); | ||
92 | }); | 96 | }); |
93 | \ No newline at end of file | 97 | \ No newline at end of file |
1 | +-----BEGIN RSA PRIVATE KEY----- | ||
2 | +MIIEpQIBAAKCAQEAq1wH6wvvKupU9Qb/OzNlQgNEQucwLrSm56lTGX0Tme56zSs5 | ||
3 | +k+44WdPQuF4xIHdzftGzna9OEat18fbdGXXrg8r2h2N7nmNkJz08DCrKQxVuyeVW | ||
4 | +y1ktKu7qzy/5rQcSKbHARB0c/L8Iv9j63ZWu2EbBoz9rAxbUxImIwuXcLELlxHL1 | ||
5 | +aD33VYB7ODqI0b/FBN2Su+4QlzaOW8Nhu2ctUDM3R0j2cpGa0rqAGjIUtCZiUeUa | ||
6 | ++TsYbJwoQg+kVN9gb06I6uDsijxVexYNeuFj+JGjQm80pXqcJn92e8G3FQISan6g | ||
7 | +BkVClr9VBlc14HV3DLFy36RuLDzkA1vmUMNd6wIDAQABAoIBACaZzaLSBmdJcCfe | ||
8 | +EqKYWkf7imXzxDPROAPZbcHBHig/w2PyR78eG42InGzbsv9YSSkZPffYZKKwWBpQ | ||
9 | +fM/ec1Y140DuVQuB4i7AqYUoInXoHxPV2K5oATe5qCVR7lFe1WWVB/WQBVaeBe+J | ||
10 | +hkFiFYfcsIQApi+E9hrrzGXy95z0enNpv8cJ1z9xVNts8oxXiFwzaY8Kcz56W5mS | ||
11 | +/XDboVI2Od+NHY3rJnWj63OLyRIBnyjYfNFMXysRZs64lRUxKvt74RB2hx+q6wlF | ||
12 | +djTEqTdMzm9tCCbGI5InXovCkXZToQ8ed+8071eohMxpFBqP6TSFEQf1Og+T8TzK | ||
13 | +JndHcMkCgYEA2gxBgGJmHVDaK7eiI7Fqg+ehI0GamTT/ZBHW6xvKHgMI54CUQ4c+ | ||
14 | +acLBctailDP2VNd0gKe1RRE10dz5Akzw+MydUASQONqoO8LU5eLuyNlI7QT259Xd | ||
15 | +Yfvw+BXUEN+WDtJNESbXhTYaO/3B7l2EzsWc6ToJRSoafiem4aEhsVUCgYEAyS9w | ||
16 | +/W2U4IiIVzke2tjRm/vb+T3OmOv1i/y2f79PnQMPJ5oNyxdtZ3axOapMv0KZXApo | ||
17 | +dWL205eYu0fYZpdVhtHuPAhK6tNi4CDPW2dGWB5dVaGfFMCF1CVoUJlpJT+DOfqp | ||
18 | +d774ID5dZ1PpvJoODcPXa3Bmh+83NbmpIrH90j8CgYEAoYD+azd25zPhxQvI/qME | ||
19 | +gBrq0ZBgECafG+HSzGXS+RPKXp5wMuxToEZuvr6XwSoTxJepZTnTHAs5T+5aSgfv | ||
20 | +XHlB8+jNYi8i+NDAnF3P+9hlGZnZv7I6vb68pyST5MOXA/dkudWJQNPn7pNwNzvx | ||
21 | +iK36IQ2pnB8pbFO2WdzdddkCgYEAoXvO+dyHb2Kn7TsQJSF7vfR/MKQHvH9JbL+/ | ||
22 | +zPJGeQUHmQXypF19l1qSDnM/fxV5+4LvLant7RD1qv2UGWTHZZwD2XPejnZ2Gui7 | ||
23 | +B+bxc7GLwTwlcIbH5OzRukApQZilQFiOxmsmxtrIJjQYnSYaubnEo5xo8Bt2+Uy5 | ||
24 | +EfxEfAkCgYEAvwGvYDdCcjozwnAdMSSHLa0rVoChet/cZTsqpagIF7zjMq9ljG2J | ||
25 | +7pK+esJeAwpGTwXSpIPWHDIOhScsL6iiKu2BRPa6NostlpUjDzciPZzrizz+okuP | ||
26 | +palma9L1DuQqUSC+Vqe25Qmnk7F+Hiw+Fu3L4pMcxw8/ZgUagMpkOHM= | ||
27 | +-----END RSA PRIVATE KEY----- |
1 | +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrXAfrC+8q6lT1Bv87M2VCA0RC5zAutKbnqVMZfROZ7nrNKzmT7jhZ09C4XjEgd3N+0bOdr04Rq3Xx9t0ZdeuDyvaHY3ueY2QnPTwMKspDFW7J5VbLWS0q7urPL/mtBxIpscBEHRz8vwi/2Prdla7YRsGjP2sDFtTEiYjC5dwsQuXEcvVoPfdVgHs4OojRv8UE3ZK77hCXNo5bw2G7Zy1QMzdHSPZykZrSuoAaMhS0JmJR5Rr5OxhsnChCD6RU32BvTojq4OyKPFV7Fg164WP4kaNCbzSlepwmf3Z7wbcVAhJqfqAGRUKWv1UGVzXgdXcMsXLfpG4sPOQDW+ZQw13r alexandr.khivrich@gmail.com |
1 | +-----BEGIN RSA PRIVATE KEY----- | ||
2 | +MIIEpAIBAAKCAQEAmHwDO+WhonC49gHe2DNx7OD16hfMU2JS3Y26AsE+dSlWiYlZ | ||
3 | +U0NWkmDgM88e3EpzxXECInn42OjjHxaAPcPsAnICmLjMHjAvUzQQXoPMbbbuPJxD | ||
4 | +aanh/NZnyeHy9xj6lrUgNvsrljRjdQ20SSAcdkcsOj4+HBBxnaFIzh+GW8Ha3b26 | ||
5 | +dBUYjOL/oxrUW0AKehpDJWlf6mzHBDa+DWCOSXK4zNI9K+y3lqeoWVIzKdrxHRfs | ||
6 | +tnhBs7/La+pU+kxGY6B1PouB+McdG3CBZ/yMUX/o4dDamTCU85VbyoLo5R2d7Pv2 | ||
7 | +P2y2i4/tS3E9mCAbmrYIUwShYVgYlWyYJnWCgQIDAQABAoIBAHZECQYVzk18/Bfh | ||
8 | +z4MEM6IzwMe1eYZaxkaMO+8TDmw0iafW3W8U1Tpm5L2KMTdOj4hdY/h1fapOxolA | ||
9 | +HGrLYGttHdJx0e7AFJSF1wRXWODndtOPp0F2v44ohQsxsg4wU3s8NCYwnNe8/j61 | ||
10 | +SFVHEIw0G3t49xcxMc2+YAdur/jNqXAR8w4GplW03K73R8Y4jPStk4KPU8MnLfKZ | ||
11 | +XWGq37hp5mVJlkDO91nxys4ZSvh2plKz3zRKfImEU99mWj7u8ZSKPpYU/LCm97FA | ||
12 | +CdweW5PIyzWKSNAV/4Ge0o015rPSAlWEfGXQ8rW08oxzgEz59YOBSsxUo+4AE5zW | ||
13 | +Gyls4AECgYEAylOrVBmzxoeNguyNlvmNsHOt8xz4XEA0RlZ6PnWSIT2PZ4NT1jAB | ||
14 | +J9g/u2Il6zLJOvnN777+4Od4aITNVdS1xUYTkbJ8pv0dZEH9nO3BSKzHgx8S/Har | ||
15 | +Rq02B2ZDvcV0r462QV/t1YXzrtcqSasyfZbiFSTQjYYRn7I0fB8LW0ECgYEAwO93 | ||
16 | +ufeogMRRb5lkI5kI85vcQChWeIwUA3HbZt6BiInmhtP8Ep9YVjamMR5bCy/m25yl | ||
17 | +IJK82gD8RDuFqjJNyUoiJuHPUonxYM/msZvshEUOoCvQQkRAG5SYlSEW083Vw6wM | ||
18 | +3b80nqYkYvNyJrhd93lfk9LBYJulOppYDOHAl0ECgYEAs2H1P+49xuH95DtI2bdO | ||
19 | +GUimzCo+RMQj1MztOx1QPypuT29PUFJlY+dFsiQ1zE7NvP0nyc0D+3Ed/0TnLJcX | ||
20 | +xdz4kq+19vPpMC+V5KGjQYT2qtlNIwsvlc0SXwMbQlCjwNb93f5oRmyp/bUE6CXh | ||
21 | +8RlqPybRxPg9/eGoyPdZQUECgYBxrGW5Lx6bh4+HljO2+ZKZnWoebuXLrpSYFvwy | ||
22 | +1sQxAzbMl5d8DWBJo3c1l3IC3F1DZT6xO2ODenMnbH5rcan8/+2xRPgW5GlQJg4A | ||
23 | +9SJcKCfe3RGeCYJP/bQMoWtGrY7V88e82swQ8Uic+Fx4TcYnad6TROhkmC+4oHli | ||
24 | +VZxYQQKBgQCx+bLdGDTfI4qYEvTyyRrTX3nv4Q31EjF2kByusObqzaliLWWnezIQ | ||
25 | +yt4WMMcIP1cT4iJoSpmahkiMBwRhvAzXsPoupGVIYoT34I5zsL8aTCRHYRza75ij | ||
26 | +ZreEZj3XBzYSDrigAIxsDyNzF6Ku1+VtGAL3gJXsJPDPKRH/88YOdw== | ||
27 | +-----END RSA PRIVATE KEY----- |
1 | +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCYfAM75aGicLj2Ad7YM3Hs4PXqF8xTYlLdjboCwT51KVaJiVlTQ1aSYOAzzx7cSnPFcQIiefjY6OMfFoA9w+wCcgKYuMweMC9TNBBeg8xttu48nENpqeH81mfJ4fL3GPqWtSA2+yuWNGN1DbRJIBx2Ryw6Pj4cEHGdoUjOH4Zbwdrdvbp0FRiM4v+jGtRbQAp6GkMlaV/qbMcENr4NYI5JcrjM0j0r7LeWp6hZUjMp2vEdF+y2eEGzv8tr6lT6TEZjoHU+i4H4xx0bcIFn/IxRf+jh0NqZMJTzlVvKgujlHZ3s+/Y/bLaLj+1LcT2YIBuatghTBKFhWBiVbJgmdYKB alexandr.khivrich@gmail.com |